Exemple #1
0
def get_random_mass_point_particles(numPoints, massRangeParams):
    """
    This function will generate a large set of points within the chosen mass
    and spin space. It will also return the corresponding PN spin coefficients
    for ease of use later (though these may be removed at some future point).

    Parameters
    ----------
    numPoints : int
        Number of systems to simulate
    massRangeParams : massRangeParameters instance
        Instance holding all the details of mass ranges and spin ranges.

    Returns
    --------
    mass : numpy.array
        List of the total masses.
    eta : numpy.array
        List of the symmetric mass ratios
    beta : numpy.array
        List of the 1.5PN beta spin coefficients
    sigma : numpy.array
        List of the 2PN sigma spin coefficients
    gamma : numpy.array
        List of the 2.5PN gamma spin coefficients
    spin1z : numpy.array
        List of the spin on the heavier body. NOTE: Body 1 is **always** the
        heavier body to remove mass,eta -> m1,m2 degeneracy
    spin2z : numpy.array
        List of the spin on the smaller body. NOTE: Body 2 is **always** the
        smaller body to remove mass,eta -> m1,m2 degeneracy
    mass1 : numpy.array
        List of the mass of the heavier body. NOTE: Body 1 is **always** the
        heavier body to remove mass,eta -> m1,m2 degeneracy
    mass2 : numpy.array
        List of the mass of the smaller body. NOTE: Body 2 is **always** the
        smaller body to remove mass,eta -> m1,m2 degeneracy
    """

    # WARNING: We expect mass1 > mass2 ALWAYS

    # First we choose the total masses from a unifrom distribution in mass
    # to the -5/3. power.
    mass = numpy.random.random(numPoints) * \
           (massRangeParams.minTotMass**(-5./3.) \
            - massRangeParams.maxTotMass**(-5./3.)) \
           + massRangeParams.maxTotMass**(-5./3.)
    mass = mass**(-3./5.)

    # Next we choose the mass ratios, this will take different limits based on
    # the value of total mass
    maxmass2 = numpy.minimum(mass/2., massRangeParams.maxMass2)
    minmass1 = numpy.maximum(massRangeParams.minMass1, mass/2.)
    mineta = numpy.maximum(massRangeParams.minCompMass \
                            * (mass-massRangeParams.minCompMass)/(mass*mass), \
                           massRangeParams.maxCompMass \
                            * (mass-massRangeParams.maxCompMass)/(mass*mass))
    # Note that mineta is a numpy.array because mineta depends on the total
    # mass. Therefore this is not precomputed in the massRangeParams instance
    if massRangeParams.minEta:
        mineta = numpy.maximum(massRangeParams.minEta, mineta)
    # Eta also restricted by chirp mass restrictions
    if massRangeParams.min_chirp_mass:
        eta_val_at_min_chirp = massRangeParams.min_chirp_mass / mass
        eta_val_at_min_chirp = eta_val_at_min_chirp**(5./3.)
        mineta = numpy.maximum(mineta, eta_val_at_min_chirp)

    maxeta = numpy.minimum(massRangeParams.maxEta, maxmass2 \
                             * (mass - maxmass2) / (mass*mass))
    maxeta = numpy.minimum(maxeta, minmass1 \
                             * (mass - minmass1) / (mass*mass))
    # max eta also affected by chirp mass restrictions
    if massRangeParams.max_chirp_mass:
        eta_val_at_max_chirp = massRangeParams.max_chirp_mass / mass
        eta_val_at_max_chirp = eta_val_at_max_chirp**(5./3.)
        maxeta = numpy.minimum(maxeta, eta_val_at_max_chirp)

    if (maxeta < mineta).any():
        errMsg = "ERROR: Maximum eta is smaller than minimum eta!!"
        raise ValueError(errMsg)
    eta = numpy.random.random(numPoints) * (maxeta - mineta) + mineta

    # Also calculate the component masses; mass1 > mass2
    diff = (mass*mass * (1-4*eta))**0.5
    mass1 = (mass + diff)/2.
    mass2 = (mass - diff)/2.
    # Check the masses are where we want them to be (allowing some floating
    # point rounding error).
    if (mass1 > massRangeParams.maxMass1*1.001).any() \
          or (mass1 < massRangeParams.minMass1*0.999).any():
        errMsg = "Mass1 is not within the specified mass range."
        raise ValueError(errMsg)
    if (mass2 > massRangeParams.maxMass2*1.001).any() \
          or (mass2 < massRangeParams.minMass2*0.999).any():
        errMsg = "Mass2 is not within the specified mass range."
        raise ValueError(errMsg)

    # Next up is the spins. First check if we have non-zero spins
    if massRangeParams.maxNSSpinMag == 0 and massRangeParams.maxBHSpinMag == 0:
        spinspin = numpy.zeros(numPoints,dtype=float)
        spin1z = numpy.zeros(numPoints,dtype=float)
        spin2z = numpy.zeros(numPoints,dtype=float)
        beta = numpy.zeros(numPoints,dtype=float)
        sigma = numpy.zeros(numPoints,dtype=float)
        gamma = numpy.zeros(numPoints,dtype=float)
        spin1z = numpy.zeros(numPoints,dtype=float)
        spin2z = numpy.zeros(numPoints,dtype=float)
    elif massRangeParams.nsbhFlag:
        # Spin 1 first
        mspin = numpy.zeros(len(mass1))
        mspin += massRangeParams.maxBHSpinMag
        spin1z = (2*numpy.random.random(numPoints) - 1) * mspin
        # Then spin2
        mspin = numpy.zeros(len(mass2))
        mspin += massRangeParams.maxNSSpinMag
        spin2z = (2*numpy.random.random(numPoints) - 1) * mspin
        # And compute the PN components that come out of this
        beta, sigma, gamma, chiS = pnutils.get_beta_sigma_from_aligned_spins(
            eta, spin1z, spin2z)
    else:        
        boundary_mass = massRangeParams.ns_bh_boundary_mass
        # Spin 1 first
        mspin = numpy.zeros(len(mass1))
        mspin += massRangeParams.maxNSSpinMag
        mspin[mass1 > boundary_mass] = massRangeParams.maxBHSpinMag
        spin1z = (2*numpy.random.random(numPoints) - 1) * mspin
        # Then spin 2
        mspin = numpy.zeros(len(mass2))
        mspin += massRangeParams.maxNSSpinMag
        mspin[mass2 > boundary_mass] = massRangeParams.maxBHSpinMag
        spin2z = (2*numpy.random.random(numPoints) - 1) * mspin
        # And compute the PN components that come out of this
        beta, sigma, gamma, chiS = pnutils.get_beta_sigma_from_aligned_spins(
            eta, spin1z, spin2z)

    return mass,eta,beta,sigma,gamma,spin1z,spin2z,mass1,mass2
Exemple #2
0
def get_random_mass_point_particles(numPoints, massRangeParams):
    """
    This function will generate a large set of points within the chosen mass
    and spin space. It will also return the corresponding PN spin coefficients
    for ease of use later (though these may be removed at some future point).

    Parameters
    ----------
    numPoints : int
        Number of systems to simulate
    massRangeParams : massRangeParameters instance
        Instance holding all the details of mass ranges and spin ranges.

    Returns
    --------
    mass : numpy.array
        List of the total masses.
    eta : numpy.array
        List of the symmetric mass ratios
    beta : numpy.array
        List of the 1.5PN beta spin coefficients
    sigma : numpy.array
        List of the 2PN sigma spin coefficients
    gamma : numpy.array
        List of the 2.5PN gamma spin coefficients
    spin1z : numpy.array
        List of the spin on the heavier body. NOTE: Body 1 is **always** the
        heavier body to remove mass,eta -> m1,m2 degeneracy
    spin2z : numpy.array
        List of the spin on the smaller body. NOTE: Body 2 is **always** the
        smaller body to remove mass,eta -> m1,m2 degeneracy
    mass1 : numpy.array
        List of the mass of the heavier body. NOTE: Body 1 is **always** the
        heavier body to remove mass,eta -> m1,m2 degeneracy
    mass2 : numpy.array
        List of the mass of the smaller body. NOTE: Body 2 is **always** the
        smaller body to remove mass,eta -> m1,m2 degeneracy
    """

    # WARNING: We expect mass1 > mass2 ALWAYS

    # First we choose the total masses from a unifrom distribution in mass
    # to the -5/3. power.
    mass = numpy.random.random(numPoints) * \
           (massRangeParams.minTotMass**(-5./3.) \
            - massRangeParams.maxTotMass**(-5./3.)) \
           + massRangeParams.maxTotMass**(-5./3.)
    mass = mass**(-3. / 5.)

    # Next we choose the mass ratios, this will take different limits based on
    # the value of total mass
    maxmass2 = numpy.minimum(mass / 2., massRangeParams.maxMass2)
    minmass1 = numpy.maximum(massRangeParams.minMass1, mass / 2.)
    mineta = numpy.maximum(massRangeParams.minCompMass \
                            * (mass-massRangeParams.minCompMass)/(mass*mass), \
                           massRangeParams.maxCompMass \
                            * (mass-massRangeParams.maxCompMass)/(mass*mass))
    # Note that mineta is a numpy.array because mineta depends on the total
    # mass. Therefore this is not precomputed in the massRangeParams instance
    if massRangeParams.minEta:
        mineta = numpy.maximum(massRangeParams.minEta, mineta)
    # Eta also restricted by chirp mass restrictions
    if massRangeParams.min_chirp_mass:
        eta_val_at_min_chirp = massRangeParams.min_chirp_mass / mass
        eta_val_at_min_chirp = eta_val_at_min_chirp**(5. / 3.)
        mineta = numpy.maximum(mineta, eta_val_at_min_chirp)

    maxeta = numpy.minimum(massRangeParams.maxEta, maxmass2 \
                             * (mass - maxmass2) / (mass*mass))
    maxeta = numpy.minimum(maxeta, minmass1 \
                             * (mass - minmass1) / (mass*mass))
    # max eta also affected by chirp mass restrictions
    if massRangeParams.max_chirp_mass:
        eta_val_at_max_chirp = massRangeParams.max_chirp_mass / mass
        eta_val_at_max_chirp = eta_val_at_max_chirp**(5. / 3.)
        maxeta = numpy.minimum(maxeta, eta_val_at_max_chirp)

    if (maxeta < mineta).any():
        errMsg = "ERROR: Maximum eta is smaller than minimum eta!!"
        raise ValueError(errMsg)
    eta = numpy.random.random(numPoints) * (maxeta - mineta) + mineta

    # Also calculate the component masses; mass1 > mass2
    diff = (mass * mass * (1 - 4 * eta))**0.5
    mass1 = (mass + diff) / 2.
    mass2 = (mass - diff) / 2.
    # Check the masses are where we want them to be (allowing some floating
    # point rounding error).
    if (mass1 > massRangeParams.maxMass1*1.001).any() \
          or (mass1 < massRangeParams.minMass1*0.999).any():
        errMsg = "Mass1 is not within the specified mass range."
        raise ValueError(errMsg)
    if (mass2 > massRangeParams.maxMass2*1.001).any() \
          or (mass2 < massRangeParams.minMass2*0.999).any():
        errMsg = "Mass2 is not within the specified mass range."
        raise ValueError(errMsg)

    # Next up is the spins. First check if we have non-zero spins
    if massRangeParams.maxNSSpinMag == 0 and massRangeParams.maxBHSpinMag == 0:
        spinspin = numpy.zeros(numPoints, dtype=float)
        spin1z = numpy.zeros(numPoints, dtype=float)
        spin2z = numpy.zeros(numPoints, dtype=float)
        beta = numpy.zeros(numPoints, dtype=float)
        sigma = numpy.zeros(numPoints, dtype=float)
        gamma = numpy.zeros(numPoints, dtype=float)
        spin1z = numpy.zeros(numPoints, dtype=float)
        spin2z = numpy.zeros(numPoints, dtype=float)
    elif massRangeParams.nsbhFlag:
        # Spin 1 first
        mspin = numpy.zeros(len(mass1))
        mspin += massRangeParams.maxBHSpinMag
        spin1z = (2 * numpy.random.random(numPoints) - 1) * mspin
        # Then spin2
        mspin = numpy.zeros(len(mass2))
        mspin += massRangeParams.maxNSSpinMag
        spin2z = (2 * numpy.random.random(numPoints) - 1) * mspin
        # And compute the PN components that come out of this
        beta, sigma, gamma, chiS = pnutils.get_beta_sigma_from_aligned_spins(
            eta, spin1z, spin2z)
    else:
        boundary_mass = massRangeParams.ns_bh_boundary_mass
        # Spin 1 first
        mspin = numpy.zeros(len(mass1))
        mspin += massRangeParams.maxNSSpinMag
        mspin[mass1 > boundary_mass] = massRangeParams.maxBHSpinMag
        spin1z = (2 * numpy.random.random(numPoints) - 1) * mspin
        # Then spin 2
        mspin = numpy.zeros(len(mass2))
        mspin += massRangeParams.maxNSSpinMag
        mspin[mass2 > boundary_mass] = massRangeParams.maxBHSpinMag
        spin2z = (2 * numpy.random.random(numPoints) - 1) * mspin
        # And compute the PN components that come out of this
        beta, sigma, gamma, chiS = pnutils.get_beta_sigma_from_aligned_spins(
            eta, spin1z, spin2z)

    return mass, eta, beta, sigma, gamma, spin1z, spin2z, mass1, mass2
Exemple #3
0
def get_point_distance(point1, point2, metricParams, fUpper):
    """
    Function to calculate the mismatch between two points, supplied in terms
    of the masses and spins, using the xi_i parameter space metric to
    approximate the mismatch of the two points. Can also take one of the points
    as an array of points and return an array of mismatches (but only one can
    be an array!)

    point1 : List of floats or numpy.arrays
        point1[0] contains the mass(es) of the heaviest body(ies).
        point1[1] contains the mass(es) of the smallest body(ies).
        point1[2] contains the spin(es) of the heaviest body(ies).
        point1[3] contains the spin(es) of the smallest body(ies).
    point2 : List of floats
        point2[0] contains the mass of the heaviest body.
        point2[1] contains the mass of the smallest body.
        point2[2] contains the spin of the heaviest body.
        point2[3] contains the spin of the smallest body.
    metricParams : metricParameters instance
        Structure holding all the options for construction of the metric
        and the eigenvalues, eigenvectors and covariance matrix
        needed to manipulate the space.
    fUpper : float
        The value of fUpper to use when getting the mu coordinates from the
        lambda coordinates. This must be a key in metricParams.evals,
        metricParams.evecs and metricParams.evecsCV
        (ie. we must know how to do the transformation for
        the given value of fUpper)

    Returns
    --------
    dist : float or numpy.array
        Distance between the point2 and all points in point1
    xis1 : List of floats or numpy.arrays
        Position of the input point1(s) in the xi_i parameter space
    xis2 : List of floats
        Position of the input point2 in the xi_i parameter space
    """
    aMass1 = point1[0]
    aMass2 = point1[1]
    aSpin1 = point1[2]
    aSpin2 = point1[3]
    try:
        leng = len(aMass1)
        aArray = True
    except:
        aArray = False

    bMass1 = point2[0]
    bMass2 = point2[1]
    bSpin1 = point2[2]
    bSpin2 = point2[3]
    bArray = False

    aTotMass = aMass1 + aMass2
    aEta = (aMass1 * aMass2) / (aTotMass * aTotMass)
    aCM = aTotMass * aEta**(3./5.)

    bTotMass = bMass1 + bMass2
    bEta = (bMass1 * bMass2) / (bTotMass * bTotMass)
    bCM = bTotMass * bEta**(3./5.)

    abeta, asigma, agamma, achis = pnutils.get_beta_sigma_from_aligned_spins(
        aEta, aSpin1, aSpin2)
    bbeta, bsigma, bgamma, bchis = pnutils.get_beta_sigma_from_aligned_spins(
        bEta, bSpin1, bSpin2)

    aXis = get_cov_params(aTotMass, aEta, abeta, asigma, agamma, achis, \
                          metricParams, fUpper)

    bXis = get_cov_params(bTotMass, bEta, bbeta, bsigma, bgamma, bchis, \
                          metricParams, fUpper)

    dist = (aXis[0] - bXis[0])**2
    for i in xrange(1,len(aXis)):
        dist += (aXis[i] - bXis[i])**2

    return dist, aXis, bXis
Exemple #4
0
def get_point_distance(point1, point2, metricParams, fUpper):
    """
    Function to calculate the mismatch between two points, supplied in terms
    of the masses and spins, using the xi_i parameter space metric to
    approximate the mismatch of the two points. Can also take one of the points
    as an array of points and return an array of mismatches (but only one can
    be an array!)

    point1 : List of floats or numpy.arrays
        point1[0] contains the mass(es) of the heaviest body(ies).
        point1[1] contains the mass(es) of the smallest body(ies).
        point1[2] contains the spin(es) of the heaviest body(ies).
        point1[3] contains the spin(es) of the smallest body(ies).
    point2 : List of floats
        point2[0] contains the mass of the heaviest body.
        point2[1] contains the mass of the smallest body.
        point2[2] contains the spin of the heaviest body.
        point2[3] contains the spin of the smallest body.
    metricParams : metricParameters instance
        Structure holding all the options for construction of the metric
        and the eigenvalues, eigenvectors and covariance matrix
        needed to manipulate the space.
    fUpper : float
        The value of fUpper to use when getting the mu coordinates from the
        lambda coordinates. This must be a key in metricParams.evals,
        metricParams.evecs and metricParams.evecsCV
        (ie. we must know how to do the transformation for
        the given value of fUpper)

    Returns
    --------
    dist : float or numpy.array
        Distance between the point2 and all points in point1
    xis1 : List of floats or numpy.arrays
        Position of the input point1(s) in the xi_i parameter space
    xis2 : List of floats
        Position of the input point2 in the xi_i parameter space
    """
    aMass1 = point1[0]
    aMass2 = point1[1]
    aSpin1 = point1[2]
    aSpin2 = point1[3]
    try:
        leng = len(aMass1)
        aArray = True
    except:
        aArray = False

    bMass1 = point2[0]
    bMass2 = point2[1]
    bSpin1 = point2[2]
    bSpin2 = point2[3]
    bArray = False

    aTotMass = aMass1 + aMass2
    aEta = (aMass1 * aMass2) / (aTotMass * aTotMass)
    aCM = aTotMass * aEta**(3. / 5.)

    bTotMass = bMass1 + bMass2
    bEta = (bMass1 * bMass2) / (bTotMass * bTotMass)
    bCM = bTotMass * bEta**(3. / 5.)

    abeta, asigma, agamma, achis = pnutils.get_beta_sigma_from_aligned_spins(
        aEta, aSpin1, aSpin2)
    bbeta, bsigma, bgamma, bchis = pnutils.get_beta_sigma_from_aligned_spins(
        bEta, bSpin1, bSpin2)

    aXis = get_cov_params(aTotMass, aEta, abeta, asigma, agamma, achis, \
                          metricParams, fUpper)

    bXis = get_cov_params(bTotMass, bEta, bbeta, bsigma, bgamma, bchis, \
                          metricParams, fUpper)

    dist = (aXis[0] - bXis[0])**2
    for i in xrange(1, len(aXis)):
        dist += (aXis[i] - bXis[i])**2

    return dist, aXis, bXis
def get_mass_distribution(bestMasses, scaleFactor, massRangeParams,
                          metricParams, fUpper,
                          numJumpPoints=100, chirpMassJumpFac=0.0001,
                          etaJumpFac=0.01, spin1zJumpFac=0.01,
                          spin2zJumpFac=0.01):
    """
    Given a set of masses, this function will create a set of points nearby
    in the mass space and map these to the xi space.

    Parameters
    -----------
    bestMasses : list
        Contains [ChirpMass, eta, spin1z, spin2z]. Points will be placed around
        tjos
    scaleFactor : float
        This parameter describes the radius away from bestMasses that points
        will be placed in.
    massRangeParams : massRangeParameters instance
        Instance holding all the details of mass ranges and spin ranges.
    metricParams : metricParameters instance
        Structure holding all the options for construction of the metric
        and the eigenvalues, eigenvectors and covariance matrix
        needed to manipulate the space.
    fUpper : float
        The value of fUpper that was used when obtaining the xi_i
        coordinates. This lets us know how to rotate potential physical points
        into the correct xi_i space. This must be a key in metricParams.evals,
        metricParams.evecs and metricParams.evecsCV
        (ie. we must know how to do the transformation for
        the given value of fUpper)
    numJumpPoints : int, optional (default = 100)
        The number of points that will be generated every iteration
    chirpMassJumpFac : float, optional (default=0.0001)
        The jump points will be chosen with fractional variation in chirpMass
        up to this multiplied by scaleFactor.
    etaJumpFac : float, optional (default=0.01)
        The jump points will be chosen with fractional variation in eta
        up to this multiplied by scaleFactor.
    spin1zJumpFac : float, optional (default=0.01)
        The jump points will be chosen with absolute variation in spin1z up to
        this multiplied by scaleFactor.
    spin2zJumpFac : float, optional (default=0.01)
        The jump points will be chosen with absolute variation in spin2z up to
        this multiplied by scaleFactor.

    Returns 
    --------
    Chirpmass : numpy.array
        chirp mass of the resulting points
    Totmass : numpy.array
        Total mass of the resulting points
    Eta : numpy.array
        Symmetric mass ratio of the resulting points
    Spin1z : numpy.array
        Spin of the heavier body of the resulting points
    Spin2z : numpy.array
        Spin of the smaller body of the resulting points
    Diff : numpy.array
        Mass1 - Mass2 of the resulting points
    Mass1 : numpy.array
        Mass1 (mass of heavier body) of the resulting points
    Mass2 : numpy.array
        Mass2 (mass of smaller body) of the resulting points
    Beta : numpy.array
        1.5PN spin phasing coefficient of the resulting points
    Sigma : numpy.array
        2PN spin phasing coefficient of the resulting points
    Gamma : numpy.array
        2.5PN spin phasing coefficient of the resulting points
    Chis : numpy.array
        0.5 * (spin1z + spin2z) for the resulting points
    new_xis : list of numpy.array
        Position of points in the xi coordinates
    """
    # FIXME: It would be better if rejected values could be drawn from the 
    # full possible mass/spin distribution. However speed in this function is
    # a major factor and must be considered.
    bestChirpmass = bestMasses[0]
    bestEta = bestMasses[1]
    bestSpin1z = bestMasses[2]
    bestSpin2z = bestMasses[3]

    # Firstly choose a set of values for masses and spins
    chirpmass = bestChirpmass * (1 - (numpy.random.random(numJumpPoints)-0.5) \
                                       * chirpMassJumpFac * scaleFactor )
    etaRange = massRangeParams.maxEta - massRangeParams.minEta
    currJumpFac = etaJumpFac * scaleFactor
    if currJumpFac > etaRange:
        currJumpFac = etaRange
    eta = bestEta * ( 1 - (numpy.random.random(numJumpPoints) - 0.5) \
                           * currJumpFac)

    maxSpinMag = max(massRangeParams.maxNSSpinMag, massRangeParams.maxBHSpinMag)
    minSpinMag = min(massRangeParams.maxNSSpinMag, massRangeParams.maxBHSpinMag)
    # Note that these two are cranged by spinxzFac, *not* spinxzFac/spinxz
    currJumpFac = spin1zJumpFac * scaleFactor
    if currJumpFac > maxSpinMag:
        currJumpFac = maxSpinMag

    # Actually set the new spin trial points
    if massRangeParams.nsbhFlag or (maxSpinMag == minSpinMag):
        curr_spin_1z_jump_fac = currJumpFac
        curr_spin_2z_jump_fac = currJumpFac
        # Check spins aren't going to be unphysical
        if currJumpFac > massRangeParams.maxBHSpinMag:
            curr_spin_1z_jump_fac = massRangeParams.maxBHSpinMag
        if currJumpFac > massRangeParams.maxNSSpinMag:
            curr_spin_2z_jump_fac = massRangeParams.maxNSSpinMag
        spin1z = bestSpin1z + ( (numpy.random.random(numJumpPoints) - 0.5) \
                            * curr_spin_1z_jump_fac)
        spin2z = bestSpin2z + ( (numpy.random.random(numJumpPoints) - 0.5) \
                            * curr_spin_2z_jump_fac)
    else:
        # If maxNSSpinMag is very low (0) and maxBHSpinMag is high we can
        # find it hard to place any points. So mix these when
        # masses are swapping between the NS and BH.
        curr_spin_bh_jump_fac = currJumpFac
        curr_spin_ns_jump_fac = currJumpFac
        # Check spins aren't going to be unphysical
        if currJumpFac > massRangeParams.maxBHSpinMag:
            curr_spin_bh_jump_fac = massRangeParams.maxBHSpinMag
        if currJumpFac > massRangeParams.maxNSSpinMag:
            curr_spin_ns_jump_fac = massRangeParams.maxNSSpinMag
        spin1z = numpy.zeros(numJumpPoints, dtype=float)
        spin2z = numpy.zeros(numJumpPoints, dtype=float)
        split_point = int(numJumpPoints/2)
        # So set the first half to be at least within the BH range and the
        # second half to be at least within the NS range
        spin1z[:split_point] = bestSpin1z + \
                            ( (numpy.random.random(split_point) - 0.5)\
                              * curr_spin_bh_jump_fac)
        spin1z[split_point:] = bestSpin1z + \
                      ( (numpy.random.random(numJumpPoints-split_point) - 0.5)\
                        * curr_spin_ns_jump_fac)
        spin2z[:split_point] = bestSpin2z + \
                            ( (numpy.random.random(split_point) - 0.5)\
                              * curr_spin_bh_jump_fac)
        spin2z[split_point:] = bestSpin2z + \
                      ( (numpy.random.random(numJumpPoints-split_point) - 0.5)\
                        * curr_spin_ns_jump_fac)

    # Point[0] is always set to the original point
    chirpmass[0] = bestChirpmass
    eta[0] = bestEta
    spin1z[0] = bestSpin1z
    spin2z[0] = bestSpin2z

    # Remove points where eta becomes unphysical
    eta[eta > massRangeParams.maxEta] = massRangeParams.maxEta
    if massRangeParams.minEta:
        eta[eta < massRangeParams.minEta] = massRangeParams.minEta
    else:
        eta[eta < 0.0001] = 0.0001

    # Total mass, masses and mass diff
    totmass = chirpmass / (eta**(3./5.))
    diff = (totmass*totmass * (1-4*eta))**0.5
    mass1 = (totmass + diff)/2.
    mass2 = (totmass - diff)/2.

    # Check the validity of the spin values
    # Do the first spin

    if maxSpinMag == 0:
        # Shortcut if non-spinning
        pass
    elif massRangeParams.nsbhFlag or (maxSpinMag == minSpinMag):
        # Simple case where I don't have to worry about correlation with mass
        numploga = abs(spin1z) > massRangeParams.maxBHSpinMag
        spin1z[numploga] = 0
    else:
        # Do have to consider masses
        boundary_mass = massRangeParams.ns_bh_boundary_mass
        numploga1 = numpy.logical_and(mass1 >= boundary_mass,
                                   abs(spin1z) <= massRangeParams.maxBHSpinMag)
        numploga2 = numpy.logical_and(mass1 < boundary_mass,
                                   abs(spin1z) <= massRangeParams.maxNSSpinMag)
        numploga = numpy.logical_or(numploga1, numploga2)
        numploga = numpy.logical_not(numploga)
        spin1z[numploga] = 0

    # Same for the second spin

    if maxSpinMag == 0:
        # Shortcut if non-spinning
        pass
    elif massRangeParams.nsbhFlag or (maxSpinMag == minSpinMag):
        numplogb = abs(spin2z) > massRangeParams.maxNSSpinMag
        spin2z[numplogb] = 0
    else:
        # Do have to consider masses
        boundary_mass = massRangeParams.ns_bh_boundary_mass
        numplogb1 = numpy.logical_and(mass2 >= boundary_mass,
                                   abs(spin2z) <= massRangeParams.maxBHSpinMag)
        numplogb2 = numpy.logical_and(mass2 < boundary_mass,
                                   abs(spin2z) <= massRangeParams.maxNSSpinMag)
        numplogb = numpy.logical_or(numplogb1, numplogb2)
        numplogb = numpy.logical_not(numplogb)
        spin2z[numplogb] = 0

    # Get the various spin-derived quantities
    beta, sigma, gamma, chis = get_beta_sigma_from_aligned_spins(eta, spin1z,
                                                                 spin2z)

    if (maxSpinMag) and (numploga[0] or numplogb[0]):
        raise ValueError("Cannot remove the guide point!")

    # And remove points where the individual masses are outside of the physical
    # range. Or the total masses are.
    # These "removed" points will have metric distances that will be much, much
    # larger than any thresholds used in the functions in brute_force_utils.py
    # and will always be rejected. An unphysical value cannot be used as it
    # would result in unphysical metric distances and cause failures.
    totmass[mass1 < massRangeParams.minMass1] = 0.0001
    totmass[mass1 > massRangeParams.maxMass1] = 0.0001
    totmass[mass2 < massRangeParams.minMass2] = 0.0001
    totmass[mass2 > massRangeParams.maxMass2] = 0.0001
    # There is some numerical error which can push this a bit higher. We do
    # *not* want to reject the initial guide point. This error comes from
    # Masses -> totmass, eta -> masses conversion, we will have points pushing
    # onto the boudaries of the space.
    totmass[totmass > massRangeParams.maxTotMass*1.0001] = 0.0001
    totmass[totmass < massRangeParams.minTotMass*0.9999] = 0.0001
    if massRangeParams.max_chirp_mass:
        totmass[chirpmass > massRangeParams.max_chirp_mass*1.0001] = 0.0001
    if massRangeParams.min_chirp_mass:
        totmass[chirpmass < massRangeParams.min_chirp_mass*0.9999] = 0.0001

    if totmass[0] < 0.00011:
        raise ValueError("Cannot remove the guide point!")

    # Then map to xis
    new_xis = get_cov_params(totmass, eta, beta, sigma, gamma, chis,
                             metricParams, fUpper)
    return chirpmass, totmass, eta, spin1z, spin2z, diff, mass1, mass2, beta, \
           sigma, gamma, chis, new_xis
Exemple #6
0
    def add_point_by_masses(self,
                            mass1,
                            mass2,
                            spin1z,
                            spin2z,
                            vary_fupper=False):
        """
        Add a point to the template bank. This differs from add point to bank
        as it assumes that the chi coordinates and the products needed to use
        vary_fupper have not already been calculated. This function calculates
        these products and then calls add_point_by_chi_coords.
        This function also
        carries out a number of sanity checks (eg. is the point within the
        ranges given by mass_range_params) that add_point_by_chi_coords does
        not do for speed concerns.

        Parameters
        -----------
        mass1 : float
            Mass of the heavier body
        mass2 : float
            Mass of the lighter body
        spin1z : float
            Spin of the heavier body
        spin2z : float
            Spin of the lighter body
        """
        # Test that masses are the expected way around (ie. mass1 > mass2)
        if mass2 > mass1:
            if not self.spin_warning_given:
                warn_msg = "Am adding a template where mass2 > mass1. The "
                warn_msg += "convention is that mass1 > mass2. Swapping mass1 "
                warn_msg += "and mass2 and adding point to bank. This message "
                warn_msg += "will not be repeated."
                logging.warn(warn_msg)
                self.spin_warning_given = True

        # These that masses obey the restrictions of mass_range_params
        if self.mass_range_params.is_outside_range(mass1, mass2, spin1z,
                                                   spin2z):
            err_msg = "Point with masses given by "
            err_msg += "%f %f %f %f " % (mass1, mass2, spin1z, spin2z)
            err_msg += "(mass1, mass2, spin1z, spin2z) is not consistent "
            err_msg += "with the provided command-line restrictions on masses "
            err_msg += "and spins."
            raise ValueError(err_msg)

        # Get beta, sigma, gamma
        tot_mass = mass1 + mass2
        eta = mass1 * mass2 / (tot_mass * tot_mass)
        beta, sigma, gamma, chis = pnutils.get_beta_sigma_from_aligned_spins(\
                                                           eta, spin1z, spin2z)

        # Get chi coordinates
        chi_coords = coord_utils.get_cov_params(tot_mass, eta, beta, sigma,
                                                gamma, chis,
                                                self.metric_params,
                                                self.ref_freq)

        # Get mus and best fupper for this point, if needed
        if vary_fupper:
            mass_dict = {}
            mass_dict['m1'] = numpy.array([mass1])
            mass_dict['m2'] = numpy.array([mass2])
            mass_dict['s1z'] = numpy.array([spin1z])
            mass_dict['s2z'] = numpy.array([spin2z])
            freqs = numpy.array([self.frequency_map.keys()], dtype=float)
            freq_cutoff = coord_utils.return_nearest_cutoff(\
                                     self.upper_freq_formula, mass_dict, freqs)
            freq_cutoff = freq_cutoff[0]
            lambdas = coord_utils.get_chirp_params(tot_mass, eta, beta, sigma,
                                                   gamma, chis,
                                                   self.metric_params.f0,
                                                   self.metric_params.pnOrder)
            mus = []
            for freq in self.frequency_map:
                mus.append(
                    coord_utils.get_mu_params(lambdas, self.metric_params,
                                              freq))
            mus = numpy.array(mus)
        else:
            freq_cutoff = None
            mus = None

        self.add_point_by_chi_coords(chi_coords,
                                     mass1,
                                     mass2,
                                     spin1z,
                                     spin2z,
                                     point_fupper=freq_cutoff,
                                     mus=mus)
Exemple #7
0
    def add_point_by_masses(self, mass1, mass2, spin1z, spin2z,
                            vary_fupper=False):
        """
        Add a point to the template bank. This differs from add point to bank
        as it assumes that the chi coordinates and the products needed to use
        vary_fupper have not already been calculated. This function calculates
        these products and then calls add_point_by_chi_coords.
        This function also
        carries out a number of sanity checks (eg. is the point within the
        ranges given by mass_range_params) that add_point_by_chi_coords does
        not do for speed concerns.

        Parameters
        -----------
        mass1 : float
            Mass of the heavier body
        mass2 : float
            Mass of the lighter body
        spin1z : float
            Spin of the heavier body
        spin2z : float
            Spin of the lighter body
        """
        # Test that masses are the expected way around (ie. mass1 > mass2)
        if mass2 > mass1:
            if not self.spin_warning_given:
                warn_msg = "Am adding a template where mass2 > mass1. The "
                warn_msg += "convention is that mass1 > mass2. Swapping mass1 "
                warn_msg += "and mass2 and adding point to bank. This message "
                warn_msg += "will not be repeated."
                logging.warn(warn_msg)
                self.spin_warning_given = True

        # These that masses obey the restrictions of mass_range_params
        if self.mass_range_params.is_outside_range(mass1, mass2, spin1z,
                                                                       spin2z):
            err_msg = "Point with masses given by "
            err_msg += "%f %f %f %f " %(mass1, mass2, spin1z, spin2z)
            err_msg += "(mass1, mass2, spin1z, spin2z) is not consistent "
            err_msg += "with the provided command-line restrictions on masses "
            err_msg += "and spins."
            raise ValueError(err_msg)

        # Get beta, sigma, gamma
        tot_mass = mass1 + mass2
        eta = mass1 * mass2 / (tot_mass * tot_mass)
        beta, sigma, gamma, chis = pnutils.get_beta_sigma_from_aligned_spins(\
                                                           eta, spin1z, spin2z)
       
        # Get chi coordinates
        chi_coords = coord_utils.get_cov_params(tot_mass, eta, beta, sigma,
                               gamma, chis, self.metric_params, self.ref_freq)

        # Get mus and best fupper for this point, if needed
        if vary_fupper:
            freq_cutoff = coord_utils.return_nearest_cutoff(\
                         self.upper_freq_formula, tot_mass, self.frequency_map)
            lambdas = coord_utils.get_chirp_params(tot_mass, eta, beta, sigma,
                                           gamma, chis, self.metric_params.f0,
                                           self.metric_params.pnOrder)
            mus = []
            for freq in self.frequency_map:
                mus.append(coord_utils.get_mu_params(lambdas,
                                                    self.metric_params, freq) )
            mus = numpy.array(mus)
        else:
            freq_cutoff=None
            mus=None

        self.add_point_by_chi_coords(chi_coords, mass1, mass2, spin1z, spin2z,
                               point_fupper=freq_cutoff, mus=mus)
Exemple #8
0
def get_chirp_params_old(mass1, mass2, spin1z, spin2z, f0, order):
    """
    Take a set of masses and spins and convert to the various lambda
    coordinates that describe the orbital phase. Accepted PN orders are:
    {}
 
    Parameters
    ----------
    mass1 : float or array
        Mass1 of input(s).
    mass2 : float or array
        Mass2 of input(s).
    spin1z : float or array
        Parallel spin component(s) of body 1.
    spin2z : float or array
        Parallel spin component(s) of body 2.
    f0 : float
        This is an arbitrary scaling factor introduced to avoid the potential
        for numerical overflow when calculating this. Generally the default
        value (70) is safe here. **IMPORTANT, if you want to calculate the
        ethinca metric components later this MUST be set equal to f_low.**
        This value must also be used consistently (ie. don't change its value
        when calling different functions!).
    order : string
        The Post-Newtonian order that is used to translate from masses and
        spins to the lambda_i coordinate system. Valid orders given above.

    Returns
    --------
    lambdas : list of floats or numpy.arrays
        The lambda coordinates for the input system(s)
    """

    totmass, eta = pnutils.mass1_mass2_to_mtotal_eta(mass1, mass2)
    beta, sigma, gamma = pnutils.get_beta_sigma_from_aligned_spins(\
               eta, spin1z, spin2z)

    # Convert mass to seconds
    totmass = totmass * MTSUN_SI
    pi = numpy.pi
    mapping = generate_inverse_mapping(order)
    lambdas = []

    for idx in xrange(len(mapping.keys())):
        if mapping[idx] == 'Lambda0':
            lambda0 = 3. / (128. * eta * (pi * totmass * f0)**(5./3.))
            lambdas.append(lambda0)
        elif mapping[idx] == 'Lambda2':
            lambda2 = 5. / (96. * pi * eta * totmass * f0) \
                      * (743./336. + 11./4. * eta)
            lambdas.append(lambda2)
        elif mapping[idx] == 'Lambda3':
            lambda3 = (-3. * pi**(1./3.))/(8. * eta * (totmass*f0)**(2./3.)) \
                      * (1. - beta/ (4. * pi))
            lambdas.append(lambda3)
        elif mapping[idx] == 'Lambda4':
            lambda4 = 15. / (64. * eta * (pi * totmass * f0)**(1./3.)) * \
                  (3058673./1016064. + 5429./1008. * eta + 617./144. * \
                   eta**2 - sigma)
            lambdas.append(lambda4)
        # No Lambda5 term is present as that would be equivalent to a constant
        # phase offset, and thus completely degenerate with the initial orbital
        # phase.
        elif mapping[idx] == 'LogLambda5':
            loglambda5 = 3. * (38645.*pi/756. - 65.*pi*eta/9. - gamma)
            loglambda5 = loglambda5 * (3./(128.*eta))
            lambdas.append(loglambda5)
        elif mapping[idx] == 'Lambda6':
            lambda6 = 11583231236531./4694215680. - (640.*pi*pi)/3.\
                      - (6848.*GAMMA)/21.
            lambda6 -= (6848./21.) * numpy.log(4 * (pi*totmass*f0)**(1./3.))
            lambda6 += (-15737765635/3048192. + 2255.*pi*pi/12.)*eta
            lambda6 += (76055.*eta*eta)/1728. - (127825.*eta*eta*eta)/1296.
            lambda6 = lambda6 * 3./(128.*eta) * (pi * totmass * f0)**(1/3.)
            lambdas.append(lambda6)
        elif mapping[idx] == 'LogLambda6':
            loglambda6 =  -( 6848./21) 
            loglambda6 = loglambda6 * 3./(128.*eta)\
                         * (pi * totmass * f0)**(1/3.)
            lambdas.append(loglambda6)
        elif mapping[idx] == 'Lambda7':
            lambda7 = (77096675.*pi)/254016. + (378515.*pi*eta)/1512. \
                      - (74045.*pi*eta*eta)/756.
            lambda7 = lambda7 * 3./(128.*eta) * (pi * totmass * f0)**(2/3.)
            lambdas.append(lambda7)
        else:
            err_msg = "Do not understand term {}.".format(mapping[idx])
            raise ValueError(err_msg)
                 
    return lambdas