Пример #1
0
def phi_3D_admix_2_and_3_into_1(phi, f2,f3, xx,yy,zz):
    """
    Admix populations 2 and 3 into population 1.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 3 populations.
    f2:       Fraction of updated population 1 to be derived from population 2. 
    f3:       Fraction of updated population 1 to be derived from population 3. 
              A fraction (1-f2-f3) will be derived from the original pop 1.
    xx,yy,zz: Mapping of points in phi to frequencies in populations 1,2 and 3.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
            = _three_pop_admixture_intermediates(phi, 1-f2-f3,f2, xx,yy,zz, xx)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    # Basically, we're splitting into a fourth ww population, then integrating
    # over yy to be left with the two populations we care about.
    idx_i = numpy.arange(phi.shape[0])
    for jj in xrange(phi.shape[1]):
        for kk in xrange(phi.shape[2]):
            phi_int = numpy.zeros((phi.shape[0], phi.shape[0]))
            phi_int[idx_i, lower_w_index[:,jj,kk]] = lower_cont[:,jj,kk]
            phi_int[idx_i, upper_w_index[:,jj,kk]] = upper_cont[:,jj,kk]
            phi[:,jj,kk] = Numerics.trapz(phi_int, xx, axis=0)

    return phi
Пример #2
0
def phi_2D_admix_2_into_1(phi, f, xx,yy):
    """
    Admix population 2 into population 1.

    Alters phi in place and returns the new version.

    phi:   phi corresponding to original 2 populations
    f:     Fraction of updated population 1 to be derived from population 2. 
             (A fraction 1-f will be derived from the original population 1.)
    xx,yy: Mapping of points in phi to frequencies in populations 1 and 2.
    """
    # Note that it's 1-f here since f now denotes the fraction coming from
    # population 2.
    lower_z_index, upper_z_index, frac_lower, frac_upper, norm \
            = _two_pop_admixture_intermediates(phi, 1-f, xx,yy,xx)

    idx_i = numpy.arange(phi.shape[0])
    lower_cont = frac_lower*norm
    upper_cont = frac_upper*norm
    for jj in xrange(len(yy)):
        phi_int = numpy.zeros((len(xx), len(xx)))
        phi_int[idx_i, lower_z_index[:,jj]] = lower_cont[:,jj]
        phi_int[idx_i, upper_z_index[:,jj]] = upper_cont[:,jj]
        phi[:,jj] = Numerics.trapz(phi_int, xx, axis=0)

    return phi
Пример #3
0
def phi_3D_admix_1_and_2_into_3(phi, f1,f2, xx,yy,zz):
    """
    Admix populations 1 and 2 into population 3.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 3 populations.
    f1:       Fraction of updated population 3 to be derived from population 1. 
    f2:       Fraction of updated population 3 to be derived from population 2. 
              A fraction (1-f1-f2) will be derived from the original pop 3.
    xx,yy,zz: Mapping of points in phi to frequencies in populations 1,2 and 3.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
            = _three_pop_admixture_intermediates(phi, f1,f2, xx,yy,zz, zz)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    # Basically, we're splitting into a fourth ww population, then integrating
    # over zz to be left with the two populations we care about.
    idx_k = numpy.arange(phi.shape[2])
    for ii in xrange(phi.shape[0]):
        for jj in xrange(phi.shape[1]):
            phi_int = numpy.zeros((phi.shape[2], phi.shape[2]))
            phi_int[idx_k, lower_w_index[ii,jj]] = lower_cont[ii,jj]
            phi_int[idx_k, upper_w_index[ii,jj]] = upper_cont[ii,jj]
            phi[ii,jj] = Numerics.trapz(phi_int, zz, axis=0)

    return phi
Пример #4
0
def phi_4D_admix_into_2(phi, f1, f3, f4, xx, yy, zz, aa):
    """
    Admix populations 1,3, and 4 into population 2.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 4 populations.
    f1:       Fraction of updated population 2 to be derived from population 1.
    f3:       Fraction of updated population 2 to be derived from population 3.
    f4:       Fraction of updated population 2 to be derived from population 4.
              A fraction (1-f1-f3-f4) will be derived from the original pop 2.
    xx,yy,zz,aa: Mapping of points in phi to frequencies in populations 1,2,3 and 4.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
        = _four_pop_admixture_intermediates(phi, f1, 1 - f1 - f3 - f4, f3, xx, yy, zz, aa, yy)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    idx_j = numpy.arange(phi.shape[1])
    for ii in range(phi.shape[0]):
        for kk in range(phi.shape[2]):
            for ll in range(phi.shape[3]):
                phi_int = numpy.zeros((phi.shape[1], phi.shape[1]))
                phi_int[idx_j, lower_w_index[ii, :, kk,
                                             ll]] = lower_cont[ii, :, kk, ll]
                phi_int[idx_j, upper_w_index[ii, :, kk,
                                             ll]] = upper_cont[ii, :, kk, ll]
                phi[ii, :, kk, ll] = Numerics.trapz(phi_int, yy, axis=0)

    return phi
Пример #5
0
def phi_2D_admix_1_into_2(phi, f, xx,yy):
    """
    Admix population 1 into population 2.

    Alters phi in place and returns the new version.

    phi:   phi corresponding to original 2 populations
    f:     Fraction of updated population 2 to be derived from population 1. 
             (A fraction 1-f will be derived from the original population 2.)
    xx,yy: Mapping of points in phi to frequencies in populations 1 and 2.
    """
    # This is just like the the split_admix situation, but we're splitting into
    # a population with zz=yy. We could do this by creating a xx by yy by yy
    # array, then integrating out the second population. That's a big waste of
    # memory, however.
    lower_z_index, upper_z_index, frac_lower, frac_upper, norm \
            = _two_pop_admixture_intermediates(phi, f, xx,yy,yy)

    # Basically, we're splitting into a third zz population, then integrating
    # over yy to be left with the two populations we care about.
    lower_cont = frac_lower*norm
    upper_cont = frac_upper*norm
    idx_j = numpy.arange(phi.shape[1])
    for ii in range(phi.shape[0]):
        phi_int = numpy.zeros((phi.shape[1], phi.shape[1]))
        # Use fancy indexing to avoid the commented out loop.
        #for jj in xrange(len(yy)):
        #    phi_int[jj, upper_z_index[ii,jj]] += frac_upper[ii,jj]*norm[ii,jj]
        #    phi_int[jj, lower_z_index[ii,jj]] += frac_lower[ii,jj]*norm[ii,jj]
        phi_int[idx_j, lower_z_index[ii]] = lower_cont[ii]
        phi_int[idx_j, upper_z_index[ii]] += upper_cont[ii]
        phi[ii] = Numerics.trapz(phi_int, yy, axis=0)

    return phi
Пример #6
0
def phi_4D_admix_into_1(phi, f2, f3, f4, xx, yy, zz, aa):
    """
    Admix populations 2, 3, and 4 into population 1.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 4 populations.
    f2:       Fraction of updated population 1 to be derived from population 2.
    f3:       Fraction of updated population 1 to be derived from population 3.
    f4:       Fraction of updated population 1 to be derived from population 4.
              A fraction (1-f2-f3-f4) will be derived from the original pop 1.
    xx,yy,zz,aa: Mapping of points in phi to frequencies in populations 1,2,3, and 4.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
        = _four_pop_admixture_intermediates(phi, 1 - f2 - f3 - f4, f2, f3, xx, yy, zz, aa, xx)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    # Basically, we're splitting into a fifth bb population, then integrating
    # over xx to be left with the two populations we care about.
    idx_i = numpy.arange(phi.shape[0])
    for jj in range(phi.shape[1]):
        for kk in range(phi.shape[2]):
            for ll in range(phi.shape[3]):
                phi_int = numpy.zeros((phi.shape[0], phi.shape[0]))
                phi_int[idx_i, lower_w_index[:, jj, kk,
                                             ll]] = lower_cont[:, jj, kk, ll]
                phi_int[idx_i, upper_w_index[:, jj, kk,
                                             ll]] = upper_cont[:, jj, kk, ll]
                phi[:, jj, kk, ll] = Numerics.trapz(phi_int, xx, axis=0)

    return phi
Пример #7
0
def phi_3D_admix_2_and_3_into_1(phi, f2, f3, xx, yy, zz):
    """
    Admix populations 2 and 3 into population 1.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 3 populations.
    f2:       Fraction of updated population 1 to be derived from population 2.
    f3:       Fraction of updated population 1 to be derived from population 3.
              A fraction (1-f2-f3) will be derived from the original pop 1.
    xx,yy,zz: Mapping of points in phi to frequencies in populations 1,2 and 3.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
        = _three_pop_admixture_intermediates(phi, 1 - f2 - f3, f2, xx, yy, zz, xx)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    # Basically, we're splitting into a fourth ww population, then integrating
    # over yy to be left with the two populations we care about.
    idx_i = numpy.arange(phi.shape[0])
    for jj in range(phi.shape[1]):
        for kk in range(phi.shape[2]):
            phi_int = numpy.zeros((phi.shape[0], phi.shape[0]))
            phi_int[idx_i, lower_w_index[:, jj, kk]] = lower_cont[:, jj, kk]
            phi_int[idx_i, upper_w_index[:, jj, kk]] = upper_cont[:, jj, kk]
            phi[:, jj, kk] = Numerics.trapz(phi_int, xx, axis=0)

    return phi
Пример #8
0
def phi_3D_admix_1_and_2_into_3(phi, f1, f2, xx, yy, zz):
    """
    Admix populations 1 and 2 into population 3.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 3 populations.
    f1:       Fraction of updated population 3 to be derived from population 1.
    f2:       Fraction of updated population 3 to be derived from population 2.
              A fraction (1-f1-f2) will be derived from the original pop 3.
    xx,yy,zz: Mapping of points in phi to frequencies in populations 1,2 and 3.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
        = _three_pop_admixture_intermediates(phi, f1, f2, xx, yy, zz, zz)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    # Basically, we're splitting into a fourth ww population, then integrating
    # over zz to be left with the two populations we care about.
    idx_k = numpy.arange(phi.shape[2])
    for ii in range(phi.shape[0]):
        for jj in range(phi.shape[1]):
            phi_int = numpy.zeros((phi.shape[2], phi.shape[2]))
            phi_int[idx_k, lower_w_index[ii, jj]] = lower_cont[ii, jj]
            phi_int[idx_k, upper_w_index[ii, jj]] = upper_cont[ii, jj]
            phi[ii, jj] = Numerics.trapz(phi_int, zz, axis=0)

    return phi
Пример #9
0
def phi_2D_admix_2_into_1(phi, f, xx, yy):
    """
    Admix population 2 into population 1.

    Alters phi in place and returns the new version.

    phi:   phi corresponding to original 2 populations
    f:     Fraction of updated population 1 to be derived from population 2.
             (A fraction 1-f will be derived from the original population 1.)
    xx,yy: Mapping of points in phi to frequencies in populations 1 and 2.
    """
    # Note that it's 1-f here since f now denotes the fraction coming from
    # population 2.
    lower_z_index, upper_z_index, frac_lower, frac_upper, norm \
        = _two_pop_admixture_intermediates(phi, 1 - f, xx, yy, xx)

    idx_i = numpy.arange(phi.shape[0])
    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm
    for jj in range(len(yy)):
        phi_int = numpy.zeros((len(xx), len(xx)))
        phi_int[idx_i, lower_z_index[:, jj]] = lower_cont[:, jj]
        phi_int[idx_i, upper_z_index[:, jj]] = upper_cont[:, jj]
        phi[:, jj] = Numerics.trapz(phi_int, xx, axis=0)

    return phi
Пример #10
0
def phi_2D_admix_1_into_2(phi, f, xx, yy):
    """
    Admix population 1 into population 2.

    Alters phi in place and returns the new version.

    phi:   phi corresponding to original 2 populations
    f:     Fraction of updated population 2 to be derived from population 1.
             (A fraction 1-f will be derived from the original population 2.)
    xx,yy: Mapping of points in phi to frequencies in populations 1 and 2.
    """
    # This is just like the the split_admix situation, but we're splitting into
    # a population with zz=yy. We could do this by creating a xx by yy by yy
    # array, then integrating out the second population. That's a big waste of
    # memory, however.
    lower_z_index, upper_z_index, frac_lower, frac_upper, norm \
        = _two_pop_admixture_intermediates(phi, f, xx, yy, yy)

    # Basically, we're splitting into a third zz population, then integrating
    # over yy to be left with the two populations we care about.
    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm
    idx_j = numpy.arange(phi.shape[1])
    for ii in range(phi.shape[0]):
        phi_int = numpy.zeros((phi.shape[1], phi.shape[1]))
        # Use fancy indexing to avoid the commented out loop.
        # for jj in range(len(yy)):
        #    phi_int[jj, upper_z_index[ii,jj]] += frac_upper[ii,jj]*norm[ii,jj]
        #    phi_int[jj, lower_z_index[ii,jj]] += frac_lower[ii,jj]*norm[ii,jj]
        phi_int[idx_j, lower_z_index[ii]] = lower_cont[ii]
        phi_int[idx_j, upper_z_index[ii]] += upper_cont[ii]
        phi[ii] = Numerics.trapz(phi_int, yy, axis=0)

    return phi
Пример #11
0
    def integrate_norm(self, params, sel_dist, theta):
        """
        """
        #need to include tuple() here to make this function play nice
        #with numpy arrays
        #compute weights for each fs
        sel_args = (self.gammas, ) + tuple(params)
        weights = sel_dist(*sel_args)

        #compute weight for the effectively neutral portion. not using
        #CDF function because I want this to be able to compute weight
        #for arbitrary mass functions
        weight_neu, err_neu = scipy.integrate.quad(sel_dist,
                                                   self.gammas[-1],
                                                   0,
                                                   args=tuple(params))

        #function's adaptable for demographic models from 1-3
        #populations but this assumes the selection coefficient is the
        #same in both populations
        pops = len(self.neu_spec.shape)
        if pops == 1:
            integrated = self.neu_spec * weight_neu + Numerics.trapz(
                weights[:, numpy.newaxis] * self.spectra, self.gammas, axis=0)
        elif pops == 2:
            integrated = self.neu_spec * weight_neu + Numerics.trapz(
                weights[:, numpy.newaxis, numpy.newaxis] * self.spectra,
                self.gammas,
                axis=0)
        elif pops == 3:
            integrated = self.neu_spec * weight_neu + Numerics.trapz(
                weights[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] *
                self.spectra,
                self.gammas,
                axis=0)
        else:
            raise IndexError("Must have one to three populations")

        integrated_fs = Spectrum(integrated, extrap_x=self.extrap_x)

        #normalization
        dist_int = Numerics.trapz(weights, self.gammas) + weight_neu
        return integrated_fs / dist_int * theta
Пример #12
0
    def integrate(self, params, sel_dist, theta):
        """
        integration without re-normalizing the DFE. This assumes the
        portion of the DFE that is not integrated is not seen in your
        sample.
        """
        #need to include tuple() here to make this function play nice
        #with numpy arrays
        sel_args = (self.gammas, ) + tuple(params)
        #compute weights for each fs
        weights = sel_dist(*sel_args)

        #compute weight for the effectively neutral portion. not using
        #CDF function because I want this to be able to compute weight
        #for arbitrary mass functions
        weight_neu, err_neu = scipy.integrate.quad(sel_dist,
                                                   self.gammas[-1],
                                                   0,
                                                   args=tuple(params))

        #function's adaptable for demographic models from 1-3 populations
        pops = len(self.neu_spec.shape)
        if pops == 1:
            integrated = self.neu_spec * weight_neu + Numerics.trapz(
                weights[:, numpy.newaxis] * self.spectra, self.gammas, axis=0)
        elif pops == 2:
            integrated = self.neu_spec * weight_neu + Numerics.trapz(
                weights[:, numpy.newaxis, numpy.newaxis] * self.spectra,
                self.gammas,
                axis=0)
        elif pops == 3:
            integrated = self.neu_spec * weight_neu + Numerics.trapz(
                weights[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] *
                self.spectra,
                self.gammas,
                axis=0)
        else:
            raise IndexError("Must have one to three populations")

        integrated_fs = Spectrum(integrated, extrap_x=self.extrap_x)

        #no normalization, allow lethal mutations to fall out
        return integrated_fs * theta
Пример #13
0
def remove_pop(phi, xx, popnum):
    """
    Remove a population from phi.

    Returns new phi with one fewer population.

    phi: phi corresponding to original populations
    xx: Mapping of points in phi to frequencies in population to be removed
    popnum: Population number to remove, numbering from 1.
    """
    return Numerics.trapz(phi, xx, axis=popnum-1)
Пример #14
0
def remove_pop(phi, xx, popnum):
    """
    Remove a population from phi.

    Returns new phi with one fewer population.

    phi: phi corresponding to original populations
    xx: Mapping of points in phi to frequencies in population to be removed
    popnum: Population number to remove, numbering from 1.
    """
    return Numerics.trapz(phi, xx, axis=popnum - 1)
Пример #15
0
def phi_5D_admix_into_5(phi, f1, f2, f3, f4, xx, yy, zz, aa, bb):
    """
    Admix populations 1, 2, 3, and 4 into population 5.

    Alters phi in place and returns the new version.

    phi:      phi corresponding to original 5 populations.
    f1:       Fraction of updated population 5 to be derived from population 1.
    f2:       Fraction of updated population 5 to be derived from population 2.
    f3:       Fraction of updated population 5 to be derived from population 3.
    f4:       Fraction of updated population 5 to be derived from population 3.
              A fraction (1-f1-f2-f3-f4) will be derived from the original pop 5.
    xx,yy,zz,aa,bb: Mapping of points in phi to frequencies in populations 1,2,3,4, and 5.
    """
    lower_w_index, upper_w_index, frac_lower, frac_upper, norm \
        = _five_pop_admixture_intermediates(phi, f1, f2, f3, f4, xx, yy, zz, aa, bb, xx)

    lower_cont = frac_lower * norm
    upper_cont = frac_upper * norm

    idx_m = numpy.arange(phi.shape[4])
    for ii in range(phi.shape[0]):
        for jj in range(phi.shape[1]):
            for kk in range(phi.shape[2]):
                for ll in range(phi.shape[3]):
                    phi_int = numpy.zeros((phi.shape[4], phi.shape[4]))
                    phi_int[idx_m,
                            lower_w_index[ii, jj, kk,
                                          ll, :]] = lower_cont[ii, jj, kk,
                                                               ll, :]
                    phi_int[idx_m,
                            upper_w_index[ii, jj, kk,
                                          ll, :]] = upper_cont[ii, jj, kk,
                                                               ll, :]
                    phi[ii, jj, kk, ll, :] = Numerics.trapz(phi_int,
                                                            xx,
                                                            axis=0)

    return phi
Пример #16
0
def demo_selection_distINV(params, ns, sel_dist, theta, cache):
    """
    sel_dist should be a function that is evaluated PDF(X) = func(x, param1, param2 ..., paramn)
    
    theta is required for now, just going to use Poisson ll
    """
    #load saved objects

    #spectra_obj = pickle.load(open('{0}spectra.obj'.format(note),'rb'))

    spectra_obj = cache

    # Note that first and last entry of SFS are meaningless!
    # The last two entries of params are now h_intercept and h_rate

    params_DFE = params[:-2]
    params_h = params[-2:]

    hvalues = comp_h_from_s_INV(spectra_obj['gammas'], *params_h)

    # Choose the closest SFS that correspond to the respective hvalues:

    hlist_idx = [find_nearest_idx(spectra_obj['hlist'], h) for h in hvalues]

    spectra_interp = numpy.array([
        spectra_obj['spectra'][hlist_idx[i], i, :]
        for i in range(spectra_obj['spectra'].shape[1])
    ])

    # For some reason, some SFS just contain nan when 2Neas*h is large...
    # For now, set them to 0 and deal with it later... they should only contain small values anyway
    # Update: THis is fixed, the problem where negative values in the SFS

    # spectra_interp = [numpy.nan_to_num(sfs) for sfs in spectra_interp]  # replaces nan with 0

    #compute weights for each SFS
    sel_args = (spectra_obj['gammas'], ) + tuple(params_DFE)
    weights = sel_dist(*sel_args)

    #compute weight for the effectively neutral portion. not using CDF function because
    #I want this to be able to compute weight for an arbitrary mass functions
    weight_neu, err_neu = scipy.integrate.quad(sel_dist,
                                               spectra_obj['gammas'][-1],
                                               0,
                                               args=tuple(params_DFE))
    weight_lethal, err_lethal = scipy.integrate.quad(sel_dist,
                                                     -numpy.inf,
                                                     spectra_obj['gammas'][0],
                                                     args=tuple(params_DFE))

    #function's adaptable for demographic models from 1-3 populations
    pops = len(spectra_obj['neu_spec'].shape)
    if pops == 1:
        integrated = spectra_obj['neu_spec'] * weight_neu + Numerics.trapz(
            weights[:, numpy.newaxis] * spectra_interp,
            spectra_obj['gammas'],
            axis=0) + spectra_interp[0] * weight_lethal
    elif pops == 2:
        integrated = spectra_obj['neu_spec'] * weight_neu + Numerics.trapz(
            weights[:, numpy.newaxis, numpy.newaxis] * spectra_interp,
            spectra_obj['gammas'],
            axis=0) + spectra_interp[0] * weight_lethal
    elif pops == 3:
        integrated = spectra_obj['neu_spec'] * weight_neu + Numerics.trapz(
            weights[:, numpy.newaxis, numpy.newaxis, numpy.newaxis] *
            spectra_interp,
            spectra_obj['gammas'],
            axis=0) + spectra_interp[0] * weight_lethal
    else:
        raise IndexError("Must have one to three populations")

    integrated_fs = Spectrum(integrated, extrap_x=spectra_obj['extrap_x'])

    # Changed this:
    # Lethal mutations now don't fall out. All lethal mutations contribute the most deleterious SFS.
    # This assumes that the range of gamma goes from small to lethal!

    return integrated_fs * theta