Example #1
0
def Msph(r, z, dr=0., ref='200c', unit='Msun', r_unit='kpc'):
    """
    Calculates the mass of a cluster with radius r, assuming it is
    spherical.

    Supported units are Msun (for M) and {Mpc,kpc} for r.

    """
    contrast = int(ref[:-1])
    # [rho] = Msun·Mpc⁻³
    rho = contrast * cosmology.density(z, ref=ref[-1], unit='astro')
    #        m = 4*pi/3 * rho*r**3
    # --> r**3 = m / (4*pi/3) / rho
    if r_unit == 'kpc':
        r = r / 1000
    m = rho * 4 * numpy.pi / 3 * r**3 # [M] = Msun

    if dr != 0.:
        dm = rho * 4 * numpy.pi * r**2 # [dM] = Msun
    # later: include alternative units
    if unit == 'Msun':
        if dr != 0:
            return m, dm
        else:
            return m
Example #2
0
def rsph(m, z, dm=0., ref='200c', unit='Mpc'):
    """
    Returns r, the radius that contains a density *contrast* times
    the critical density, assuming a spherical distribution, given a
    mass m,
    
    m = (4·pi/3)·r³·(contrast·rho_c)

    If an error on the mass is provided, also returns the error in r.
        *Input:
    m: the mass of the cluster, in solar masses. Can be an
        uncertainties.ufloat as well, in which case *r* will be
        returned with the same type.
    z: the redshift of the cluster
    dm: the uncertainty on the mass, in solar masses
    contrast: the density contrast with respect to the critical (or
        average) density of the Universe at redshift z.
        *Returns:
    r: the spherical radius, in kpc
    dr: the uncertainty on r, in kpc -- if dm is given

    """
    contrast = int(ref[:-1])
    # [rho] = Msun·Mpc⁻³
    rho = contrast * cosmology.density(z, ref=ref[-1], unit='astro')
    #        m = 4*pi/3 * rho*r**3
    # --> r**3 = m / (4*pi/3) / rho
    r = (m / (4 * numpy.pi / 3) / rho) ** (1. / 3.) # [r] = Mpc
    if dm != 0. and type(m) != uncertainties.Variable:
        dr = 1 / (4 * numpy.pi) * 1 / (rho * r ** 2) * dm # [dr] = Mpc
        if unit == 'kpc':
            return 1e3 * r, 1e3 * dr
        if unit == 'Mpc':
            return r, dr
    if unit == 'kpc':
        return 1e3 * r
    if unit == 'Mpc':
        return r
Example #3
0
def nfw(m, z, dm=0, ref_in='200c', ref_out='500c',
        c=1., err=1e-6, scaling='duffy08', full_output=False):
    """
    Convert the mass of a cluster from one overdensity radius to another
    assuming an NFW profile.

    Parameters
    ----------
        m         : float
                    mass, in units of solar mass
        z         : float
                    redshift
        dm        : float (optional)
                    mass uncertainty
        ref_in    : {'2500c', '500c', '200c', '180c', '100c',
                    '500a', '200a', '100a'} (default '200c')
                    overdensity at which the input mass is measured.
                    The last letter indicates whether the overdensity
                    is with respect to the critical ('c') or average
                    ('a') density of the Universe at redshift z.
        ref_out   : {'2500c', '500c', '200c', '180c', '100c',
                    '500a', '200a', '100a'} (default '500c')
                    overdensity at which the output mass is measured.
        c         : float (default 1)
                    either a fixed concentration or a correction factor
                    to the Duffy et al. relation (useful, e.g., for
                    estimating uncertainties due to the c-M relation).
                    See parameter duffy.
        err       : float (default 1e-6)
                    allowed difference for convergence
        scaling   : {'duffy08', 'dutton14'} (optional)
                    If given, use the corresponding concentration
                    relation with a correction factor *c*. If False,
                    the concentration is fixed to the value of *c*.
                    Only possible if ref_in is either '200c' or '200a'.
        full_output : bool (default False)
                    If True, also return the concentration used.

    Returns
    -------
        m_out     : float
                    The mass at the output overdensity. If dm>0 then an
                    uncertainty on this mass is also returned (m_out is
                    then a tuple of length 2).
        c         : float (optional)
                    concentration. This is returned if full_output is
                    set to True.

    """

    #if ref_in != '200c':
        #return read_nfw(m, z, dm, ref_in=ref_in, ref_out=ref_out)
    if ref_in not in ('200a', '200c'):
        duffy = False

    if not numpy.iterable(m):
        m = numpy.array([m])
    if not numpy.iterable(dm):
        dm = numpy.array([dm])

    # iteratively calculate output mass
    def _mass(c, mx, scale, err):
        mx_out = 0
        mass = mx
        while abs(mx_out/mass - 1) > err:
            mx_out = mass
            r_out = (3 * mx_out / (4 * numpy.pi * rho_out)) ** (1./3.)
            x = r_out / scale
            mass = mx * (numpy.log(1 + x) - x / (1 + x)) / \
                   (numpy.log(1 + c) - c / (1 + c))
        return mass

    # density contrasts
    rho_in = int(ref_in[:-1]) * cosmology.density(z, ref=ref_in[-1])
    rho_out = int(ref_out[:-1]) * cosmology.density(z, ref=ref_out[-1])

    # radii
    r_in = conversions.rsph(m, z, ref=ref_in, unit='Mpc')
    if scaling in ('duffy08', 'dutton14'):
        c = c * scalings.cM(m, z, ref=ref_in, scaling=scaling)
    scale = r_in / c
    # mass and uncertainty (if defined)
    m_out = numpy.array([_mass(ci, mi, rs, err)
                         for ci, mi, rs in izip(c, m, scale)])
    if numpy.any(dm > 0):
        dm_hi = numpy.array([_mass(ci, mi+dmi, rs, err)
                             for ci, mi, dmi, rs in izip(c, m, dm, scale)])
        dm_lo = numpy.array([_mass(ci, mi-dmi, rs, err)
                             for ci, mi, dmi, rs in izip(c, m, dm, scale)])
        m_out = (m_out, (dm_hi+dm_lo)/2)

    if full_output:
        return m_out, c
    return m_out