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
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
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)