def test_ecorr_backend(self):
            """Test that ecorr-backend signal returns correct values."""
            # set up signal parameter
            ecorr = parameter.Uniform(-10, -5)
            selection = Selection(selections.by_backend)
            ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr,
                                            selection=selection)
            ecm = ec(self.psr)

            ecc = gp_signals.EcorrBasisModel(log10_ecorr=ecorr,
                                             selection=selection,
                                             coefficients=True)
            eccm = ecc(self.psr)

            # parameters
            ecorrs = [-6.1, -6.2, -6.3, -6.4]
            params = {
                "B1855+09_basis_ecorr_430_ASP_log10_ecorr": ecorrs[0],
                "B1855+09_basis_ecorr_430_PUPPI_log10_ecorr": ecorrs[1],
                "B1855+09_basis_ecorr_L-wide_ASP_log10_ecorr": ecorrs[2],
                "B1855+09_basis_ecorr_L-wide_PUPPI_log10_ecorr": ecorrs[3],
            }

            fmat = ecm.get_basis(params)
            cf = 1e-6 * np.random.randn(fmat.shape[1])
            d1 = np.dot(fmat, cf)

            for key in ecm._keys:
                parname = "B1855+09_basis_ecorr_" + key + "_coefficients"
                params[parname] = cf[ecm._slices[key]]
            d2 = eccm.get_delay(params)

            msg = "Implicit and explicit ecorr-basis delays are different."
            assert np.allclose(d1, d2), msg
        def test_formalism(self):
            # create marginalized model
            ef = white_signals.MeasurementNoise(
                efac=parameter.Uniform(0.1, 5.0))
            tm = gp_signals.TimingModel()
            ec = gp_signals.EcorrBasisModel(
                log10_ecorr=parameter.Uniform(-10, -5))
            pl = utils.powerlaw(log10_A=parameter.Uniform(-18, -12),
                                gamma=parameter.Uniform(1, 7))
            rn = gp_signals.FourierBasisGP(spectrum=pl, components=10)
            model = ef + tm + ec + rn
            pta = signal_base.PTA([model(self.psr)])

            # create hierarchical model
            tmc = gp_signals.TimingModel(coefficients=True)
            ecc = gp_signals.EcorrBasisModel(log10_ecorr=parameter.Uniform(
                -10, -5),
                                             coefficients=True)
            rnc = gp_signals.FourierBasisGP(spectrum=pl,
                                            components=10,
                                            coefficients=True)
            modelc = ef + tmc + ecc + rnc
            ptac = signal_base.PTA([modelc(self.psr)])

            ps = {
                "B1855+09_efac": 1,
                "B1855+09_basis_ecorr_log10_ecorr": -6,
                "B1855+09_red_noise_log10_A": -14,
                "B1855+09_red_noise_gamma": 3,
            }
            psc = utils.get_coefficients(pta, ps)

            d1 = ptac.get_delay(psc)[0]
            d2 = (np.dot(pta.pulsarmodels[0].signals[1].get_basis(ps),
                         psc["B1855+09_linear_timing_model_coefficients"]) +
                  np.dot(pta.pulsarmodels[0].signals[2].get_basis(ps),
                         psc["B1855+09_basis_ecorr_coefficients"]) +
                  np.dot(pta.pulsarmodels[0].signals[3].get_basis(ps),
                         psc["B1855+09_red_noise_coefficients"]))

            msg = "Implicit and explicit PTA delays are different."
            assert np.allclose(d1, d2), msg

            l1 = pta.get_lnlikelihood(ps)
            l2 = ptac.get_lnlikelihood(psc)

            # I don't know how to integrate l2 to match l1...
            msg = "Marginal and hierarchical likelihoods should be different."
            assert l1 != l2, msg
    def test_ecorr(self):
        """Test that ecorr signal returns correct values."""
        # set up signal parameter
        ecorr = parameter.Uniform(-10, -5)
        ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr)
        ecm = ec(self.psr)

        # parameters
        ecorr = -6.4
        params = {"B1855+09_basis_ecorr_log10_ecorr": ecorr}

        # basis matrix test
        U = utils.create_quantization_matrix(self.psr.toas)[0]
        msg = "U matrix incorrect for Basis Ecorr signal."
        assert np.allclose(U, ecm.get_basis(params)), msg

        # Jvec test
        jvec = 10 ** (2 * ecorr) * np.ones(U.shape[1])
        msg = "Prior vector incorrect for Basis Ecorr signal."
        assert np.all(ecm.get_phi(params) == jvec), msg

        # inverse Jvec test
        msg = "Prior vector inverse incorrect for Basis Ecorr signal."
        assert np.all(ecm.get_phiinv(params) == 1 / jvec), msg

        # test shape
        msg = "U matrix shape incorrect"
        assert ecm.get_basis(params).shape == U.shape, msg
    def add_ecorr(self):
        """Return dictionary containing correlated white noise (ECORR) signal
        attributes

        :return: OrderedDict of ECORR signal
        """
        ecorr_dct = dict()
        ecorr = parameter.Uniform(-10.0, -4.0)
        ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr,
                                        selection=self.selection)
        self.ecorr_sig = ec(self.psr)
        for ii, param in enumerate(self.ecorr_sig.param_names):
            Nvec = np.ones_like(self.psr.toaerrs) * self.ecorr_sig._masks[ii]
            Jvec = np.array(np.sum(Nvec * self.Umat.T, axis=1) > 0.0,
                            dtype=np.double)
            newsignal = OrderedDict({
                'type': 'ecorr',
                'name': param,
                'pmin': [-10.0],
                'pmax': [-4.0],
                'pstart': [-6.5],
                'interval': [True],
                'numpars': 1,
                'Jvec': Jvec
            })
            ecorr_dct.update({param: newsignal})

        return ecorr_dct
    def test_compare_ecorr_likelihood(self):
        """Compare basis and kernel ecorr methods."""

        selection = Selection(selections.nanograv_backends)
        ef = white_signals.MeasurementNoise()
        ec = white_signals.EcorrKernelNoise(selection=selection)
        ec2 = gp_signals.EcorrBasisModel(selection=selection)
        tm = gp_signals.TimingModel()
        m = ef + ec + tm
        m2 = ef + ec2 + tm

        pta1 = signal_base.PTA([m(p) for p in self.psrs])
        pta2 = signal_base.PTA([m2(p) for p in self.psrs])

        params = parameter.sample(pta1.params)
        l1 = pta1.get_lnlikelihood(params)

        # need to translate some names for EcorrBasis
        basis_params = {}
        for parname, parval in params.items():
            if "log10_ecorr" in parname:
                toks = parname.split("_")
                basisname = toks[0] + "_basis_ecorr_" + "_".join(toks[1:])
                basis_params[basisname] = parval
        params.update(basis_params)
        l2 = pta2.get_lnlikelihood(params)

        msg = "Likelihood mismatch between ECORR methods"
        assert np.allclose(l1, l2), msg
    def test_ecorr_backend(self):
        """Test that ecorr-backend signal returns correct values."""
        # set up signal parameter
        ecorr = parameter.Uniform(-10, -5)
        selection = Selection(selections.by_backend)
        ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr, selection=selection)
        ecm = ec(self.psr)

        # parameters
        ecorrs = [-6.1, -6.2, -6.3, -6.4]
        params = {
            "B1855+09_basis_ecorr_430_ASP_log10_ecorr": ecorrs[0],
            "B1855+09_basis_ecorr_430_PUPPI_log10_ecorr": ecorrs[1],
            "B1855+09_basis_ecorr_L-wide_ASP_log10_ecorr": ecorrs[2],
            "B1855+09_basis_ecorr_L-wide_PUPPI_log10_ecorr": ecorrs[3],
        }

        # get the basis
        bflags = self.psr.backend_flags
        Umats = []
        for flag in np.unique(bflags):
            mask = bflags == flag
            Umats.append(
                utils.create_quantization_matrix(self.psr.toas[mask])[0])
        nepoch = sum(U.shape[1] for U in Umats)
        U = np.zeros((len(self.psr.toas), nepoch))
        jvec = np.zeros(nepoch)
        netot = 0
        for ct, flag in enumerate(np.unique(bflags)):
            mask = bflags == flag
            nn = Umats[ct].shape[1]
            U[mask, netot:nn + netot] = Umats[ct]
            jvec[netot:nn + netot] = 10**(2 * ecorrs[ct])
            netot += nn

        # basis matrix test
        msg = "U matrix incorrect for Basis Ecorr-backend signal."
        assert np.allclose(U, ecm.get_basis(params)), msg

        # Jvec test
        msg = "Prior vector incorrect for Basis Ecorr backend signal."
        assert np.all(ecm.get_phi(params) == jvec), msg

        # inverse Jvec test
        msg = "Prior vector inverse incorrect for Basis Ecorr backend signal."
        assert np.all(ecm.get_phiinv(params) == 1 / jvec), msg

        # test shape
        msg = "U matrix shape incorrect"
        assert ecm.get_basis(params).shape == U.shape, msg
Beispiel #7
0
def initialize_pta_sim(psrs, fgw,
                       inc_efac=True, inc_equad=False, inc_ecorr=False,
                       selection=None,
                       inc_red_noise=False, noisedict=None):
    
    # continuous GW signal
    s = models.cw_block_circ(log10_fgw=np.log10(fgw), psrTerm=True)
    
    # linearized timing model
    s += gp_signals.TimingModel(use_svd=True)

    # white noise
    if selection == 'backend':
        selection = selections.Selection(selections.by_backend)

    if inc_efac:
        efac = parameter.Constant()
        s += white_signals.MeasurementNoise(efac=efac, selection=selection)
    
    if inc_equad:
        equad = parameter.Constant()
        s += white_signals.EquadNoise(log10_equad=equad,
                                      selection=selection)
    if inc_ecorr:
        ecorr = parameter.Constant()
        s += gp_signals.EcorrBasisModel(log10_ecorr=ecorr,
                                        selection=selection)

    if inc_red_noise:
        log10_A = parameter.Constant()
        gamma = parameter.Constant()
        pl = utils.powerlaw(log10_A=log10_A, gamma=gamma)
        s += gp_signals.FourierBasisGP(pl, components=30)

    model = [s(psr) for psr in psrs]
    pta = signal_base.PTA(model)

    # set white noise parameters
    if noisedict is None:
        print('No noise dictionary provided!...')
    else:
        pta.set_default_params(noisedict)
    
    return pta
    def test_combine_signals(self):
        """Test for combining different signals."""
        # set up signal parameter
        ecorr = parameter.Uniform(-10, -5)
        ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr)

        pl = utils.powerlaw(log10_A=parameter.Uniform(-18, -12), gamma=parameter.Uniform(1, 7))
        rn = gp_signals.FourierBasisGP(spectrum=pl, components=30)

        log10_sigma = parameter.Uniform(-10, -5)
        log10_lam = parameter.Uniform(np.log10(86400), np.log10(1500 * 86400))
        basis = create_quant_matrix(dt=7 * 86400)
        prior = se_kernel(log10_sigma=log10_sigma, log10_lam=log10_lam)
        se = gp_signals.BasisGP(prior, basis, name="se")

        ts = gp_signals.TimingModel()

        s = ec + rn + ts + se
        m = s(self.psr)

        # parameters
        ecorr = -6.4
        log10_A, gamma = -14.5, 4.33
        log10_lam, log10_sigma = 7.4, -6.4
        params = {
            "B1855+09_basis_ecorr_log10_ecorr": ecorr,
            "B1855+09_red_noise_log10_A": log10_A,
            "B1855+09_red_noise_gamma": gamma,
            "B1855+09_se_log10_lam": log10_lam,
            "B1855+09_se_log10_sigma": log10_sigma,
        }

        # combined basis matrix
        U = utils.create_quantization_matrix(self.psr.toas)[0]
        M = self.psr.Mmat.copy()
        norm = np.sqrt(np.sum(M ** 2, axis=0))
        M /= norm
        F, f2 = utils.createfourierdesignmatrix_red(self.psr.toas, nmodes=30)
        U2, avetoas = create_quant_matrix(self.psr.toas, dt=7 * 86400)
        T = np.hstack((U, F, M, U2))

        # combined prior vector
        jvec = 10 ** (2 * ecorr) * np.ones(U.shape[1])
        phim = np.ones(self.psr.Mmat.shape[1]) * 1e40
        phi = utils.powerlaw(f2, log10_A=log10_A, gamma=gamma)
        K = se_kernel(avetoas, log10_lam=log10_lam, log10_sigma=log10_sigma)
        phivec = np.concatenate((jvec, phi, phim))
        phi = sl.block_diag(np.diag(phivec), K)
        phiinv = np.linalg.inv(phi)

        # basis matrix test
        msg = "Basis matrix incorrect for combined signal."
        assert np.allclose(T, m.get_basis(params)), msg

        # Kernal test
        msg = "Prior matrix incorrect for combined signal."
        assert np.allclose(m.get_phi(params), phi), msg

        # inverse Kernel test
        msg = "Prior matrix inverse incorrect for combined signal."
        assert np.allclose(m.get_phiinv(params), phiinv), msg

        # test shape
        msg = "Basis matrix shape incorrect size for combined signal."
        assert m.get_basis(params).shape == T.shape, msg
Beispiel #9
0
def white_noise_block(vary=False,
                      inc_ecorr=False,
                      gp_ecorr=False,
                      efac1=False,
                      select='backend',
                      name=None):
    """
    Returns the white noise block of the model:

        1. EFAC per backend/receiver system
        2. EQUAD per backend/receiver system
        3. ECORR per backend/receiver system

    :param vary:
        If set to true we vary these parameters
        with uniform priors. Otherwise they are set to constants
        with values to be set later.
    :param inc_ecorr:
        include ECORR, needed for NANOGrav channelized TOAs
    :param gp_ecorr:
        whether to use the Gaussian process model for ECORR
    :param efac1:
        use a strong prior on EFAC = Normal(mu=1, stdev=0.1)
    """

    if select == 'backend':
        # define selection by observing backend
        backend = selections.Selection(selections.by_backend)
        # define selection by nanograv backends
        backend_ng = selections.Selection(selections.nanograv_backends)
    else:
        # define no selection
        backend = selections.Selection(selections.no_selection)

    # white noise parameters
    if vary:
        if efac1:
            efac = parameter.Normal(1.0, 0.1)
        else:
            efac = parameter.Uniform(0.01, 10.0)
        equad = parameter.Uniform(-8.5, -5)
        if inc_ecorr:
            ecorr = parameter.Uniform(-8.5, -5)
    else:
        efac = parameter.Constant()
        equad = parameter.Constant()
        if inc_ecorr:
            ecorr = parameter.Constant()

    # white noise signals
    ef = white_signals.MeasurementNoise(efac=efac,
                                        selection=backend,
                                        name=name)
    eq = white_signals.EquadNoise(log10_equad=equad,
                                  selection=backend,
                                  name=name)
    if inc_ecorr:
        if gp_ecorr:
            if name is None:
                ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr,
                                                selection=backend_ng)
            else:
                ec = gp_signals.EcorrBasisModel(log10_ecorr=ecorr,
                                                selection=backend_ng,
                                                name=name)

        else:
            ec = white_signals.EcorrKernelNoise(log10_ecorr=ecorr,
                                                selection=backend_ng,
                                                name=name)

    # combine signals
    if inc_ecorr:
        s = ef + eq + ec
    elif not inc_ecorr:
        s = ef + eq

    return s
    def test_conditional_gp(self):
        ef = white_signals.MeasurementNoise(efac=parameter.Uniform(0.1, 5.0))
        tm = gp_signals.TimingModel()
        ec = gp_signals.EcorrBasisModel(log10_ecorr=parameter.Uniform(-10, -5))
        pl = utils.powerlaw(log10_A=parameter.Uniform(-18, -12),
                            gamma=parameter.Uniform(1, 7))
        rn = gp_signals.FourierBasisGP(spectrum=pl,
                                       components=10,
                                       combine=False)

        model = ef + tm + ec + rn
        pta = signal_base.PTA([model(self.psr), model(self.psr2)])

        p0 = {
            "B1855+09_basis_ecorr_log10_ecorr": -6.051740765663904,
            "B1855+09_efac": 2.9027266737466095,
            "B1855+09_red_noise_gamma": 6.9720332277819725,
            "B1855+09_red_noise_log10_A": -16.749192700991543,
            "B1937+21_basis_ecorr_log10_ecorr": -9.726747733721872,
            "B1937+21_efac": 3.959178240268702,
            "B1937+21_red_noise_gamma": 2.9030772884814797,
            "B1937+21_red_noise_log10_A": -17.978562921948992,
        }

        c = utils.ConditionalGP(pta)
        cmean = c.get_mean_coefficients(p0)

        # build index for the global coefficient vector
        idx, ntot = {}, 0
        for l, v in cmean.items():
            idx[l] = slice(ntot, ntot + len(v))
            ntot = ntot + len(v)

        # repeat the computation using the common-signal formalism
        TNrs = pta.get_TNr(p0)
        TNTs = pta.get_TNT(p0)
        phiinvs = pta.get_phiinv(p0, logdet=False, method="cliques")

        TNr = np.concatenate(TNrs)
        Sigma = sps.block_diag(TNTs, "csc") + sps.block_diag(
            [np.diag(phiinvs[0]), np.diag(phiinvs[1])])

        ch = cholesky(Sigma)
        mn = ch(TNr)
        iSigma = sps.linalg.inv(Sigma)

        # check mean values
        msg = "Conditional GP coefficient value does not match"
        for l, v in cmean.items():
            assert np.allclose(mn[idx[l]], v, atol=1e-4, rtol=1e-4), msg

        # check variances
        par = "B1937+21_linear_timing_model_coefficients"
        c1 = np.cov(
            np.array([cs[par] for cs in c.sample_coefficients(p0, n=10000)]).T)
        c2 = iSigma[idx[par], idx[par]].toarray().T
        msg = "Conditional GP coefficient variance does not match"
        assert np.allclose(c1, c2, atol=1e-4, rtol=1e-4), msg

        # check mean processes
        proc = "B1937+21_linear_timing_model"
        p1 = c.get_mean_processes(p0)[proc]
        p2 = np.dot(pta["B1937+21"]["linear_timing_model"].get_basis(),
                    mn[idx[par]])
        msg = "Conditional GP time series does not match"
        assert np.allclose(p1, p2, atol=1e-4, rtol=1e-4), msg

        # check mean of sampled processes
        p2 = np.mean(np.array(
            [pc[proc] for pc in c.sample_processes(p0, n=1000)]),
                     axis=0)
        msg = "Mean of sampled conditional GP processes does not match"
        assert np.allclose(p1, p2, atol=1e-4, rtol=1e-4)

        # now try with a common process

        crn = gp_signals.FourierBasisCommonGP(spectrum=pl,
                                              orf=utils.hd_orf(),
                                              components=10,
                                              combine=False)

        model = ef + tm + ec + crn
        pta = signal_base.PTA([model(self.psr), model(self.psr2)])

        p0 = {
            "B1855+09_basis_ecorr_log10_ecorr": -5.861847220080768,
            "B1855+09_efac": 4.588342210948306,
            "B1937+21_basis_ecorr_log10_ecorr": -9.151872649912377,
            "B1937+21_efac": 0.8947815819783302,
            "common_fourier_gamma": 6.638289750637263,
            "common_fourier_log10_A": -15.68180643904114,
        }

        c = utils.ConditionalGP(pta)
        cmean = c.get_mean_coefficients(p0)

        idx, ntot = {}, 0
        for l, v in cmean.items():
            idx[l] = slice(ntot, ntot + len(v))
            ntot = ntot + len(v)

        TNrs = pta.get_TNr(p0)
        TNTs = pta.get_TNT(p0)
        phiinvs = pta.get_phiinv(p0, logdet=False, method="cliques")

        TNr = np.concatenate(TNrs)
        Sigma = sps.block_diag(TNTs, "csc") + sps.csc_matrix(phiinvs)

        ch = cholesky(Sigma)
        mn = ch(TNr)

        msg = "Conditional GP coefficient value does not match for common GP"
        for l, v in cmean.items():
            assert np.allclose(mn[idx[l]], v)