示例#1
0
def spher_harms(l, m, inclination):
    """Return spherical harmonic polarizations
    """

    # FIXME: we are using spin -2 weighted spherical harmonics for now,
    # when possible switch to spheroidal harmonics.
    Y_lm = lal.SpinWeightedSphericalHarmonic(inclination, 0., -2, l, m).real
    Y_lminusm = lal.SpinWeightedSphericalHarmonic(inclination, 0., -2, l, -m).real
    Y_plus = Y_lm + (-1)**l * Y_lminusm
    Y_cross = Y_lm - (-1)**l * Y_lminusm

    return Y_plus, Y_cross
示例#2
0
def sum_modes(hlms, inclination, phi):
    """Applies spherical harmonics and sums modes to produce a plus and cross
    polarization.

    Parameters
    ----------
    hlms : dict
        Dictionary of ``(l, m)`` -> complex ``hlm``. The ``hlm`` may be a
        complex number or array, or complex ``TimeSeries``. All modes in the
        dictionary will be summed.
    inclination : float
        The inclination to use.
    phi : float
        The phase to use.

    Returns
    -------
    complex float or array
        The plus and cross polarization as a complex number. The real part
        gives the plus, the negative imaginary part the cross.
    """
    out = None
    for mode in hlms:
        l, m = mode
        hlm = hlms[l, m]
        ylm = lal.SpinWeightedSphericalHarmonic(inclination, phi, -2, l, m)
        if out is None:
            out = ylm * hlm
        else:
            out += ylm * hlm
    return out
示例#3
0
def construct_Hlm(Ixx, Ixy, Ixz, Iyy, Iyz, Izz, l=2, abs_m=2, geom=False):
    """
    Construct the expansion parameters Hlm from T1000553.  Returns the expansion
    parameters for l, m= +/- abs_m as a dictionary with key names for the
    m-index
    """

    if l!=2:
        print "l!=2 not supported"
        sys.exit()
    if abs_m>2:
        print "Only l=2 supported, |m| must be <=2"
        sys.exit()
    if abs_m!=2:
        print "Actually, only supporting |m|=2 for now, bye!"
        sys.exit()

    if abs_m==2:
        #H2n2 = np.sqrt(4.0*lal.PI/5.0) * (Ixx - Iyy + 2*1j*Ixy)
        #H2p2 = np.sqrt(4.0*lal.PI/5.0) * (Ixx - Iyy - 2*1j*Ixy)

        fac = 1/lal.SpinWeightedSphericalHarmonic(0, 0, -2, 2, 2).real

        H2n2 = fac * (Ixx - Iyy + 2*1j*Ixy)
        H2p2 = fac * (Ixx - Iyy - 2*1j*Ixy)

        if geom==False:
            H2n2 *= lal.G_SI / lal.C_SI**4
            H2p2 *= lal.G_SI / lal.C_SI**4

    return {'l=2, m=-2':H2n2,'l=2, m=2':H2p2}
示例#4
0
def gen_pycbc_waveform(mass1, mass2, approximant, delta_t=1./8192, f_lower=30, distance=1, t1=None, t2=None, *args, **kwargs):
    q = mass1/mass2
    mtot = mass1 + mass2
    hp, hc = waveform.get_td_waveform(approximant=approximant,
                             mass1=mass1,
                             mass2=mass2,
                             delta_t=delta_t,
                             f_lower=f_lower,
                             distance=distance)
    times = phenom.StoM(hp.sample_times.numpy(), mtot)
    ylm = np.abs(lal.SpinWeightedSphericalHarmonic(0,0,-2,2,2))
    amp_scale = utils.td_amp_scale(mtot, distance) * ylm
    hp_array = hp.numpy() / amp_scale
    hc_array = hc.numpy() / amp_scale

    h_array = hp_array - 1.j*hc_array

    if t1 is None:
        t1 = times[0]
    if t2 is None:
        t2 = times[-1]

    mask = (times >= t1) & (times <= t2)

    times = times[mask]
    h_array = h_array[mask]

    return times, h_array
示例#5
0
def project_waveform(Hlm, theta, phi, distance=20.0):
    """
    Project the expansion parameters in the dictionary Hlm onto the sky for
    co-latitude theta, azimuth phi. 

    Returns hplus, hcross for a given theta, phi

    """

    colatitude_indices=[2]
    azimuth_indices=[-2,2]

    hplus=0.0
    hcross=0.0

    h = np.zeros(len(Hlm['l=2, m=2']), dtype=complex)

    # See e.g., pycbc/waveform/nr_waveform.py
    for l in colatitude_indices:
        for m in azimuth_indices:


            sYlm = lal.SpinWeightedSphericalHarmonic(theta, phi, -2, l, m)
            curr_Hlm = Hlm['l=%i, m=%i'%(l, m)]

#            h+=curr_Hlm * sYlm

            curr_hp = curr_Hlm.real * sYlm.real - curr_Hlm.imag * sYlm.imag
            curr_hc = -curr_Hlm.real*sYlm.imag - curr_Hlm.imag * sYlm.real
 
            hplus  += curr_hp
            hcross += curr_hc 

#    hplus = h.real
#    hcross = -1*h.imag
    
    # Scale by distance


    distance*=1e6*lal.PC_SI
    hplus /= distance
    hcross /= distance

    # Scale up by 40% for quadrupole approximation
    hplus*=1.4
    hcross*=1.4

    #hplus = taper_start(hplus)
    #hcross = taper_start(hcross)
    # Window:
    window = lal.CreateTukeyREAL8Window(len(hplus), 0.1)
    #hplus *= window.data.data
    #hcross *= window.data.data

    hplus  = pycbc.types.TimeSeries(initial_array=hplus,  delta_t = 1.0/16384)
    hcross = pycbc.types.TimeSeries(initial_array=hcross, delta_t = 1.0/16384)

    return hplus, hcross
示例#6
0
def call_lalfunc(Lmax, theta, phi, selected_modes=None): 
	
	for l in range(2, Lmax+1):
		for m in range(-l, l+1):
			if selected_modes is not None and (l,m) not in selected_modes:
				continue
			for i in xrange(0, len(theta)):
				lal.SpinWeightedSphericalHarmonic(theta[i], phi[i], -2, l, m)
	return
def compute_spherical_harmonics(Lmax, theta, phi, selected_modes=None):
    """
    Return a dictionary keyed by tuples
    (l,m)
    that contains the values of all
    -2Y_lm(theta,phi)
    with
    l <= Lmax
    -l <= m <= l
    """
    # PRB: would this be faster if we made it a 2d numpy array?  
    Ylms = {}
    for l in range(2,Lmax+1):
        for m in range(-l,l+1):
            if selected_modes is not None and (l,m) not in selected_modes:
                continue
            Ylms[ (l,m) ] = lal.SpinWeightedSphericalHarmonic(theta, phi,-2, l, m)

    return Ylms
示例#8
0
 def complex_hoft(self,
                  force_T=False,
                  deltaT=1. / 16384,
                  time_over_M_zero=0.,
                  sgn=-1):
     hlmT = self.hlmoft(force_T, deltaT, time_over_M_zero)
     npts = hlmT[(2, 2)].data.length
     wfmTS = lal.CreateCOMPLEX16TimeSeries(
         "Psi4", lal.LIGOTimeGPS(0.), 0., deltaT,
         lalsimutils.lsu_DimensionlessUnit, npts)
     wfmTS.data.data[:] = 0  # SHOULD NOT BE NECESARY, but the creation operator doesn't robustly clean memory
     wfmTS.epoch = hlmT[(2, 2)].epoch
     for mode in hlmT.keys():
         # PROBLEM: Be careful with interpretation. The incl and phiref terms are NOT tied to L.
         if rosDebug:
             print(mode, np.max(hlmT[mode].data.data), " running max ",
                   np.max(np.abs(wfmTS.data.data)))
         wfmTS.data.data += np.exp(
             -2 * sgn * 1j * self.P.psi
         ) * hlmT[mode].data.data * lal.SpinWeightedSphericalHarmonic(
             self.P.incl, -self.P.phiref, -2, int(mode[0]), int(mode[1]))
     return wfmTS
示例#9
0
def get_glm(l, m, theta):
    r"""The maginitude of the :math:`{}_{-2}Y_{\ell m}`.

    The spin-weighted spherical harmonics can be written as
    :math:`{}_{-2}Y_{\ell m}(\theta, \phi) = g_{\ell m}(\theta)e^{i m \phi}`.
    This returns the `g_{\ell m}(\theta)` part. Note that this is real.

    Parameters
    ----------
    l : int
        The :math:`\ell` index of the spherical harmonic.
    m : int
        The :math:`m` index of the spherical harmonic.
    theta : float
        The polar angle (in radians).

    Returns
    -------
    float :
        The amplitude of the harmonic at the given polar angle.
    """
    return lal.SpinWeightedSphericalHarmonic(theta, 0., -2, l, m).real
示例#10
0
    def _loglr(self, return_unmarginalized=False):
        r"""Computes the log likelihood ratio,

        .. math::

            \log \mathcal{L}(\Theta) = \sum_i
                \left<h_i(\Theta)|d_i\right> -
                \frac{1}{2}\left<h_i(\Theta)|h_i(\Theta)\right>,

        at the current parameter values :math:`\Theta`.

        Returns
        -------
        float
            The value of the log likelihood ratio.
        """
        params = self.current_params
        try:
            wfs = self.waveform_generator.generate(**params)
        except NoWaveformError:
            return self._nowaveform_loglr()
        except FailedWaveformError as e:
            if self.ignore_failed_waveforms:
                return self._nowaveform_loglr()
            else:
                raise e

        # ---------------------------------------------------------------------
        # Some optimizations not yet taken:
        # * higher m calculations could have a lot of redundancy
        # * fp/fc need not be calculated except where polarization is different
        # * may be possible to simplify this by making smarter use of real/imag
        # ---------------------------------------------------------------------
        lr = 0.
        hds = {}
        hhs = {}
        for det, modes in wfs.items():
            if det not in self.dets:
                self.dets[det] = Detector(det)

            fp, fc = self.dets[det].antenna_pattern(self.current_params['ra'],
                                                    self.current_params['dec'],
                                                    self.pol,
                                                    self.current_params['tc'])

            # loop over modes and prepare the waveform modes
            # we will sum up zetalm = glm <ulm, d> + i glm <vlm, d>
            # over all common m so that we can apply the phase once
            zetas = {}
            rlms = {}
            slms = {}
            for mode in modes:
                l, m = mode
                ulm, vlm = modes[mode]

                # whiten the waveforms
                # the kmax of the waveforms may be different than internal kmax
                kmax = min(max(len(ulm), len(vlm)), self._kmax[det])
                slc = slice(self._kmin[det], kmax)
                ulm[self._kmin[det]:kmax] *= self._weight[det][slc]
                vlm[self._kmin[det]:kmax] *= self._weight[det][slc]

                # the inner products
                # <ulm, d>
                ulmd = ulm[slc].inner(self._whitened_data[det][slc]).real
                # <vlm, d>
                vlmd = vlm[slc].inner(self._whitened_data[det][slc]).real

                # add inclination, and pack into a complex number
                import lal
                glm = lal.SpinWeightedSphericalHarmonic(
                    self.current_params['inclination'], 0, -2, l, m).real

                if m not in zetas:
                    zetas[m] = 0j
                zetas[m] += glm * (ulmd + 1j*vlmd)

                # Get condense set of the parts of the waveform that only diff
                # by m, this is used next to help calculate <h, h>
                r = glm * ulm
                s = glm * vlm

                if m not in rlms:
                    rlms[m] = r
                    slms[m] = s
                else:
                    rlms[m] += r
                    slms[m] += s

            # now compute all possible <hlm, hlm>
            rr_m = {}
            ss_m = {}
            rs_m = {}
            sr_m = {}
            combos = itertools.combinations_with_replacement(rlms.keys(), 2)
            for m, mprime in combos:
                r = rlms[m]
                s = slms[m]
                rprime = rlms[mprime]
                sprime = slms[mprime]
                rr_m[mprime, m] = r[slc].inner(rprime[slc]).real
                ss_m[mprime, m] = s[slc].inner(sprime[slc]).real
                rs_m[mprime, m] = s[slc].inner(rprime[slc]).real
                sr_m[mprime, m] = r[slc].inner(sprime[slc]).real
                # store the conjugate for easy retrieval later
                rr_m[m, mprime] = rr_m[mprime, m]
                ss_m[m, mprime] = ss_m[mprime, m]
                rs_m[m, mprime] = sr_m[mprime, m]
                sr_m[m, mprime] = rs_m[mprime, m]
            # now apply the phase to all the common ms
            hpd = 0.
            hcd = 0.
            hphp = 0.
            hchc = 0.
            hphc = 0.
            for m, zeta in zetas.items():
                phase_coeff = self.phase_fac(m)

                # <h+, d> = (exp[i m phi] * zeta).real()
                # <hx, d> = -(exp[i m phi] * zeta).imag()
                z = phase_coeff * zeta
                hpd += z.real
                hcd -= z.imag

                # now calculate the contribution to <h, h>
                cosm = phase_coeff.real
                sinm = phase_coeff.imag

                for mprime in zetas:
                    pcprime = self.phase_fac(mprime)

                    cosmprime = pcprime.real
                    sinmprime = pcprime.imag
                    # needed components
                    rr = rr_m[m, mprime]
                    ss = ss_m[m, mprime]
                    rs = rs_m[m, mprime]
                    sr = sr_m[m, mprime]
                    # <hp, hp>
                    hphp += rr * cosm * cosmprime \
                        + ss * sinm * sinmprime \
                        - rs * cosm * sinmprime \
                        - sr * sinm * cosmprime
                    # <hc, hc>
                    hchc += rr * sinm * sinmprime \
                        + ss * cosm * cosmprime \
                        + rs * sinm * cosmprime \
                        + sr * cosm * sinmprime
                    # <hp, hc>
                    hphc += -rr * cosm * sinmprime \
                        + ss * sinm * cosmprime \
                        + sr * sinm * sinmprime \
                        - rs * cosm * cosmprime

            # Now apply the polarizations and calculate the loglr
            # We have h = Fp * hp + Fc * hc
            # loglr = <h, d> - <h, h>/2
            #       = Fp*<hp, d> + Fc*<hc, d>
            #          - (1/2)*(Fp*Fp*<hp, hp> + Fc*Fc*<hc, hc>
            #                   + 2*Fp*Fc<hp, hc>)
            # (in the last line we have made use of the time series being
            #  real, so that <a, b> = <b, a>).
            hd = fp * hpd + fc * hcd
            hh = fp * fp * hphp + fc * fc * hchc + 2 * fp * fc * hphc
            hds[det] = hd
            hhs[det] = hh
            lr += hd - 0.5 * hh

        if return_unmarginalized:
            return self.pol, self.phase, lr, hds, hhs

        lr_total = special.logsumexp(lr) - numpy.log(self.nsamples)

        # store the maxl values
        idx = lr.argmax()
        setattr(self._current_stats, 'maxl_polarization', self.pol[idx])
        setattr(self._current_stats, 'maxl_phase', self.phase[idx])
        return float(lr_total)
    def rescale_wave(self, M=None, inclination=None, phi=None, distance=None):
        """ Rescale modes and polarizations to given mass, angles, distance.
            Note that this function re-sets the stored values of binary parameters
            and so all future calculations will assume new values unless otherwise
            specified.
        """
        #{{{
        #
        # If MASS has changed, rescale modes
        #
        if self.totalmass != M and M is not None:
            # Rescale the time-axis for all modes
            self.rescaledmodes_real, self.rescaledmodes_imag = {}, {}
            for modeL in np.arange( 2, self.modeLmax+1 ):
                self.rescaledmodes_real[modeL], self.rescaledmodes_imag[modeL] = {}, {}
                for modeM in np.arange( -1*modeL, modeL+1 ):
                    if self.skipM0 and modeM==0: continue
                    self.rescaledmodes_real[modeL][modeM], \
                    self.rescaledmodes_imag[modeL][modeM] = \
                              self.rescale_mode(M, modeL=modeL, modeM=modeM)
            self.totalmass = M
        elif self.totalmass == None and M == None:
            raise IOError("Please provide a total-mass value to rescale")

        #
        # Now rescale with distance and ANGLES
        #
        if inclination is not None: self.inclination = inclination
        if phi is not None: self.phi = phi
        if distance is not None: self.distance = distance

        # Mass / distance scaling pre-factor
        scalefac = self.totalmass * lal.MRSUN_SI / self.distance / lal.PC_SI

        # Orbital phase at the time of merger (time of amplitude peak)
        amp22 = self.get_mode_amplitude(totalmass=self.totalmass,
                                        modeL=2, modeM=2, dimensionless=False)
        iPeak, aPeak = self.get_peak_amplitude(amp=amp22)
        #phase22 = self.get_mode_phase(totalmass=self.totalmass, dimensionless=False)
        #phiOrbMerger = phase22[iPeak] / 2.

        # Combine all modes
        hp, hc = np.zeros(self.n, dtype=float), np.zeros(self.n, dtype=float)

        for modeL in np.arange( 2, self.modeLmax+1 ):
            for modeM in np.arange( -1*modeL, modeL+1 ):
                if self.skipM0 and modeM==0: continue
                # h+ - \ii hx = \Sum Ylm * hlm
                ArcTan2Merger = np.arctan2(self.rescaledmodes_imag[modeL][modeM].data[iPeak],\
                    self.rescaledmodes_real[modeL][modeM].data[iPeak])

                if self.verbose:
                  print "arctan2 at merger after: ", ArcTan2Merger

                #curr_ylm = np.exp(1 * modeM * phiOrbMerger * 1j)
                curr_ylm = np.exp(-1 * ArcTan2Merger * 1j)
                if self.debug and curr_ylm: print curr_ylm / np.abs(curr_ylm)
                curr_ylm *= lal.SpinWeightedSphericalHarmonic(\
                                self.inclination, self.phi, -2, modeL, modeM)
                if self.debug and curr_ylm: print curr_ylm / np.abs(curr_ylm)
                #
                if self.debug:
                  print ( np.arctan2(curr_ylm.imag, curr_ylm.real) + (modeM*phiOrbMerger) ) / np.pi,\
                        ( np.arctan2(curr_ylm.imag, curr_ylm.real) + (ArcTan2Merger) ) / np.pi
                  print ( np.arctan2(curr_ylm.imag, curr_ylm.real) - (modeM*phiOrbMerger) ) / np.pi,\
                        ( np.arctan2(curr_ylm.imag, curr_ylm.real) - (ArcTan2Merger) ) / np.pi
                ##
                hp += self.rescaledmodes_real[modeL][modeM].data * curr_ylm.real - \
                      self.rescaledmodes_imag[modeL][modeM].data * curr_ylm.imag
                hc -= self.rescaledmodes_real[modeL][modeM].data * curr_ylm.imag + \
                      self.rescaledmodes_imag[modeL][modeM].data * curr_ylm.real
        if self.debug: print "END\n\n"

        # Scale amplitude by mass and distance factors
        self.rescaled_hp = TimeSeries(scalefac * hp, delta_t=self.dt, epoch=0)
        self.rescaled_hc = TimeSeries(scalefac * hc, delta_t=self.dt, epoch=0)

        return [self.rescaled_hp, self.rescaled_hc]
def ApproximatePrecessingFisherMatrixElementFactor(P, p1,p2,m,s,psd,phase_deriv_cache=None,omit_geometric_factor=False,break_out_beta=False,**kwargs):
    """
    ApproximatePrecessingFisherMatrixElementFactor computes the weighted integral appearing in the sum, and the SNR weight.

    Ideally this calculation should CACHE existing phase derivatives (eg. by top-level user)
    Arguments:
       - phase_deriv_cache        : derivative of dphase/d\lambda for different parameters
       - omit_geometric_factor  : 
    """

    # Create basic infrastructure for IP. This requires VERY DENSE sampling...try to avoid
    # hF0 = lalsimutils.complex_hoff(P)
    # IP = lalsimutils.CreateCompatibleComplexIP(hF0,psd=psd,**kwargs)
    # dPsi2F_func =  interp1d(fvals,dPsi2F, fill_value=0, bounds_error=False)
    # dalphaF_func= interp

#    print " called  on ", p1,p2, m, s

    # This geometric stuff is all in common. I should make one call to generate Sh once and for all
    beta_0 = P.extract_param('beta')
    thetaJN_0 = P.extract_param('thetaJN')
    mc_s = P.extract_param('mc')/lal.MSUN_SI *lalsimutils.MsunInSec
    d_s  = P.extract_param('dist')/lal.C_SI  # distance in seconds

    if omit_geometric_factor:
        geometric_factor=1
    else:
        geometric_factor = np.abs(lal.SpinWeightedSphericalHarmonic(thetaJN_0,0,-2,2,int(m)) * lal.WignerDMatrix(2,m,s,0,beta_0,0))**2
    if np.abs(geometric_factor) < 1e-5:
        return 0,0  # saves lots of time

    # Create phase derivatives. Interpolate onto grid?  OR use lower-density sampling
    if phase_deriv_cache:
        if not (p1 in phase_deriv_cache.keys()):
            phase_deriv_cache[p1] =  PhaseDerivativeSeries(P,p1)
        else:
            fvals,fmax_safe, dPsi2F,dPhiF, dalphaF,dgammaF = phase_deriv_cache[p1]            
        if not (p2 in phase_deriv_cache.keys()):
            phase_deriv_cache[p2] =  PhaseDerivativeSeries(P,p2)
        else:
            fvals,fmax_safe, dPsi2F_2,dPhiF_2, dalphaF_2,dgammaF_2 =phase_deriv_cache[p2]            
    else:
        fvals,fmax_safe, dPsi2F,dPhiF, dalphaF,dgammaF = PhaseDerivativeSeries(P,p1)
        fvals,fmax_safe, dPsi2F_2,dPhiF_2, dalphaF_2,dgammaF_2 = PhaseDerivativeSeries(P,p2)

    dropme = np.logical_or(fvals <P.fmin, fvals>0.98*fmax_safe)

    Shvals = np.array(map(psd, np.abs(fvals)))
    Shvals[np.isnan(Shvals)]=float('inf')
    phase_weights =  4* (np.pi*mc_s*mc_s)**2/(3*d_s*d_s) *np.power((np.pi*mc_s*np.maximum(np.abs(fvals),P.fmin/2)),-7./3.)/Shvals  # hopefully one-sided. Note the P.fmin removes nans 
    phase_weights[np.isnan(phase_weights)]=0
    phase_weights[dropme] =0

    dalphaF[dropme] = 0
    dPsi2F[dropme] = 0
    dgammaF[dropme]=0

    dalphaF_2[dropme] = 0
    dPsi2F_2[dropme] = 0
    dgammaF_2[dropme]=0

    rhoms2 = np.sum(phase_weights*P.deltaF)*geometric_factor

    if (beta_0) < 1e-2:  # Pathological, cannot calculate alpha or gamma
        ret_weights = P.deltaF*phase_weights*geometric_factor*( dPsi2F)*(dPsi2F_2)
        ret = np.sum(ret_weights)
    else:
        if not break_out_beta:
            ret_weights = P.deltaF*phase_weights*geometric_factor*( dPsi2F- 2 *dgammaF + m*s*dalphaF)*(dPsi2F_2 - 2*dgammaF_2+m*s*dalphaF_2)
            ret = np.sum(ret_weights)
        else:
            # Warming: this uses the explicit assumption \gamma - -alpha cos beta
            # Warning: you probably never want this unless geometric_factor=1
            if not omit_geometric_factor:
                print(" You are extracting a breakdown of the fisher matrix versus beta, but are not fixing  the geometric factor...are you sure?")
            ret_00 = np.sum(P.deltaF*phase_weights*geometric_factor*( dPsi2F)*(dPsi2F_2 ))
            ret_01 = np.sum(P.deltaF*phase_weights*geometric_factor*( dPsi2F)*(dalphaF_2 ))
            ret_10 = np.sum(P.deltaF*phase_weights*geometric_factor*( dalphaF)*(dPsi2F_2 ))
            ret_11 = np.sum(P.deltaF*phase_weights*geometric_factor*( dalphaF)*(dalphaF_2))
            print("  -- submatrix ", p1,p2, ret_00, ret_01, ret_10, ret_11)
            return rhoms2,{"00":ret_00, "01":ret_01, "10": ret_10, "11": ret_11}

#    print " Internal fisher element", geometric_factor, rhoms2, ret
    # plt.plot(fvals,ret_weights)
    # plt.ylim(0,np.max(ret_weights))
    # plt.show()
             
    return rhoms2, ret
示例#13
0
def compute_spherical_harmonics(Lmax, theta, phi, selected_modes=None):
    """
    Return a dictionary keyed by tuples
    (l,m)
    that contains the values of all
    -2Y_lm(theta,phi)
    with
    l <= Lmax
    -l <= m <= l
    """
    Ylms = _compute_sph_l_eq_2(theta, phi, selected_modes)
    Ylms.update(_compute_sph_l_eq_3(theta, phi, selected_modes))
    Ylms.update(_compute_sph_l_eq_4(theta, phi, selected_modes))
    Ylms.update(_compute_sph_l_eq_5(theta, phi, selected_modes))
    Ylms.update(_compute_sph_l_eq_6(theta, phi, selected_modes))

    return Ylms


if __name__ == "__main__":
    theta, phi = np.random.uniform(0, pi, 2)

    # Do unit tests
    Ylm = compute_spherical_harmonics(2, theta, phi, None)
    for (l, m), val in Ylm.iteritems():
        if np.isclose(lal.SpinWeightedSphericalHarmonic(theta, phi, -2, l, m),
                      val):
            print("Test successful for (l,m) = (%d, %d)" % (l, m))
        else:
            print("Test unsucessful for (l,m) = (%d, %d)" % (l, m))
示例#14
0
def get_fd_qnm(template=None, **kwargs):
    """Return a frequency domain damped sinusoid.

    Parameters
    ----------
    template: object
        An object that has attached properties. This can be used to substitute
        for keyword arguments. A common example would be a row in an xml table.
    f_0 : float
        The ringdown-frequency.
    tau : float
        The damping time of the sinusoid.
    amp : float
        The amplitude of the ringdown (constant for now).
    phi : float
        The initial phase of the ringdown. Should also include the information
        from the azimuthal angle (phi_0 + m*Phi).
    inclination : {0., float}, optional
        Inclination of the system in radians. Default is 0 (face on).
    l : {2, int}, optional
        l mode for the spherical harmonics. Default is l=2.
    m : {2, int}, optional
        m mode for the spherical harmonics. Default is m=2.
    t_0 :  {0, float}, optional
        The starting time of the ringdown.
    delta_f : {None, float}, optional
        The frequency step used to generate the ringdown.
        If None, it will be set to the inverse of the time at which the
        amplitude is 1/1000 of the peak amplitude.
    f_lower: {None, float}, optional
        The starting frequency of the output frequency series.
        If None, it will be set to delta_f.
    f_final : {None, float}, optional
        The ending frequency of the output frequency series.
        If None, it will be set to the frequency at which the amplitude is 
        1/1000 of the peak amplitude.

    Returns
    -------
    hplustilde: FrequencySeries
        The plus phase of the ringdown in frequency domain.
    hcrosstilde: FrequencySeries
        The cross phase of the ringdown in frequency domain.
    """

    input_params = props(template, qnm_required_args, **kwargs)

    f_0 = input_params.pop('f_0')
    tau = input_params.pop('tau')
    amp = input_params.pop('amp')
    phi = input_params.pop('phi')
    # the following have defaults, and so will be populated
    t_0 = input_params.pop('t_0')
    # the following may not be in input_params
    inc = input_params.pop('inclination', 0.)
    l = input_params.pop('l', 2)
    m = input_params.pop('m', 2)
    delta_f = input_params.pop('delta_f', None)
    f_lower = input_params.pop('f_lower', None)
    f_final = input_params.pop('f_final', None)

    if delta_f is None:
        delta_f = 1. / qnm_time_decay(tau, 1./1000)
    if f_lower is None:
        f_lower = delta_f
        kmin = 0
    else:
        kmin = int(f_lower / delta_f)
    if f_final is None:
        f_final = qnm_freq_decay(f_0, tau, 1./1000)
    if f_final > max_freq:
            f_final = max_freq
    kmax = int(f_final / delta_f) + 1

    freqs = numpy.arange(kmin, kmax)*delta_f

    # FIXME: we are using spin -2 weighted spherical harmonics for now,
    # when possible switch to spheroidal harmonics.
    sph_lm = lal.SpinWeightedSphericalHarmonic(inc, 0., -2, l, m).real
    sph_lminusm = lal.SpinWeightedSphericalHarmonic(inc, 0., -2, l, -m).real
    spherical_plus = sph_lm + (-1)**l * sph_lminusm
    spherical_cross = sph_lm - (-1)**l * sph_lminusm

    denominator = 1 + (4j * pi * freqs * tau) - (4 * pi_sq * ( freqs*freqs - f_0*f_0) * tau*tau)
    norm = amp * tau / denominator
    if t_0 != 0:
        time_shift = numpy.exp(-1j * two_pi * freqs * t_0) 
        norm *= time_shift

    # Analytical expression for the Fourier transform of the ringdown (damped sinusoid)
    hp_tilde = norm * spherical_plus * ( (1 + 2j * pi * freqs * tau) * numpy.cos(phi)
                                        - two_pi * f_0 * tau * numpy.sin(phi) )
    hc_tilde = norm * spherical_cross * ( (1 + 2j * pi * freqs * tau) * numpy.sin(phi)
                                        + two_pi * f_0 * tau * numpy.cos(phi) )

    hplustilde = FrequencySeries(zeros(kmax, dtype=complex128), delta_f=delta_f)
    hcrosstilde = FrequencySeries(zeros(kmax, dtype=complex128), delta_f=delta_f)
    hplustilde.data[kmin:kmax] = hp_tilde
    hcrosstilde.data[kmin:kmax] = hc_tilde

    return hplustilde, hcrosstilde
示例#15
0
def get_td_qnm(template=None, taper=None, **kwargs):
    """Return a time domain damped sinusoid.

    Parameters
    ----------
    template: object
        An object that has attached properties. This can be used to substitute
        for keyword arguments. A common example would be a row in an xml table.
    taper: {None, float}, optional
        Tapering at the beginning of the waveform with duration taper * tau.
        This option is recommended with timescales taper=1./2 or 1. for
        time-domain ringdown-only injections.
        The abrupt turn on of the ringdown can cause issues on the waveform
        when doing the fourier transform to the frequency domain. Setting
        taper will add a rapid ringup with timescale tau/10.
    f_0 : float
        The ringdown-frequency.
    tau : float
        The damping time of the sinusoid.
    amp : float
        The amplitude of the ringdown (constant for now).
    phi : float
        The initial phase of the ringdown. Should also include the information
        from the azimuthal angle (phi_0 + m*Phi)
    inclination : {0., float}, optional
        Inclination of the system in radians. Default is 0 (face on).
    l : {2, int}, optional
        l mode for the spherical harmonics. Default is l=2.
    m : {2, int}, optional
        m mode for the spherical harmonics. Default is m=2.
    delta_t : {None, float}, optional
        The time step used to generate the ringdown.
        If None, it will be set to the inverse of the frequency at which the
        amplitude is 1/1000 of the peak amplitude.
    t_final : {None, float}, optional
        The ending time of the output time series.
        If None, it will be set to the time at which the amplitude is 
        1/1000 of the peak amplitude.

    Returns
    -------
    hplus: TimeSeries
        The plus phase of the ringdown in time domain.
    hcross: TimeSeries
        The cross phase of the ringdown in time domain.
    """

    input_params = props(template, qnm_required_args, **kwargs)
    
    f_0 = input_params.pop('f_0')
    tau = input_params.pop('tau')
    amp = input_params.pop('amp')
    phi = input_params.pop('phi')
    # the following may not be in input_params
    inc = input_params.pop('inclination', 0.)
    l = input_params.pop('l', 2)
    m = input_params.pop('m', 2)
    delta_t = input_params.pop('delta_t', None)
    t_final = input_params.pop('t_final', None)

    if delta_t is None:
        delta_t = 1. / qnm_freq_decay(f_0, tau, 1./1000)
        if delta_t < min_dt:
            delta_t = min_dt
    if t_final is None:
        t_final = qnm_time_decay(tau, 1./1000)
    kmax = int(t_final / delta_t) + 1

    times = numpy.arange(kmax) * delta_t

    # FIXME: we are using spin -2 weighted spherical harmonics for now,
    # when possible switch to spheroidal harmonics.
    sph_lm = lal.SpinWeightedSphericalHarmonic(inc, 0., -2, l, m).real
    sph_lminusm = lal.SpinWeightedSphericalHarmonic(inc, 0., -2, l, -m).real
    spherical_plus = sph_lm + (-1)**l * sph_lminusm
    spherical_cross = sph_lm - (-1)**l * sph_lminusm

    hp = amp * spherical_plus * numpy.exp(-times/tau) * \
                                numpy.cos(two_pi*f_0*times + phi)
    hc = amp * spherical_cross * numpy.exp(-times/tau) * \
                                numpy.sin(two_pi*f_0*times + phi)

    # If size of tapering window is less than delta_t, do not apply taper.
    if taper is None or delta_t > taper*tau:
        hplus = TimeSeries(zeros(kmax), delta_t=delta_t)
        hcross = TimeSeries(zeros(kmax), delta_t=delta_t)
        hplus.data[:kmax] = hp
        hcross.data[:kmax] = hc

        return hplus, hcross

    else:
        taper_hp, taper_hc, taper_window, start = apply_taper(delta_t, taper,
                                                        f_0, tau, amp, phi)
        hplus = TimeSeries(zeros(taper_window+kmax), delta_t=delta_t)
        hcross = TimeSeries(zeros(taper_window+kmax), delta_t=delta_t)
        hplus.data[:taper_window] = taper_hp
        hplus.data[taper_window:] = hp
        hplus._epoch = start
        hcross.data[:taper_window] = taper_hc
        hcross.data[taper_window:] = hc
        hcross._epoch = start

        return hplus, hcross
示例#16
0
        filename = args[1] + "_l2m%d.asc" % m
    elif len(args) == 1:
        filename = "MPI_BNSmerger_1-35_1-35_l2m%d.asc" % m
    else:
        print >> sys.stderr, "error, incorrect number of input arguments"

    # Ensure initialisation to zero
    hplus_sim.data.data = np.zeros(int(duration * sample_rate))
    hcross_sim.data.data = np.zeros(int(duration * sample_rate))

    # Spin-weighted spherical harmonic term
    if SI:
        # Then compute the spherical harmonic term explicitly
        theta *= lal.LAL_PI_180
        phi *= lal.LAL_PI_180
        sYlm = lal.SpinWeightedSphericalHarmonic(theta, phi, -2, 2, m)
    else:
        # otherwise, the spherical harmonic term is computed @ line 191 of
        # NRWaveInject.c
        sYlm = 1.0

    for i in range(len(sim_data)):

        Idotdot[0, 0] = sim_data[i, 1]
        Idotdot[0, 1] = sim_data[i, 2]
        Idotdot[0, 2] = sim_data[i, 3]

        Idotdot[1, 0] = sim_data[i, 1]
        Idotdot[1, 1] = sim_data[i, 4]
        Idotdot[1, 2] = sim_data[i, 5]