def test_free_spec_prior(self): """Test that red noise signal returns correct values.""" # set up signal parameter pr = gp_priors.free_spectrum( log10_rho=parameter.Uniform(-10, -4, size=30)) basis = gp_bases.createfourierdesignmatrix_red(nmodes=30) rn = gp_signals.BasisGP(priorFunction=pr, basisFunction=basis, name="red_noise") rnm = rn(self.psr) # parameters rhos = np.random.uniform(-10, -4, size=30) params = {"B1855+09_red_noise_log10_rho": rhos} # basis matrix test F, f2 = gp_bases.createfourierdesignmatrix_red(self.psr.toas, nmodes=30) msg = "F matrix incorrect for free spectrum." assert np.allclose(F, rnm.get_basis(params)), msg # spectrum test phi = gp_priors.free_spectrum(f2, log10_rho=rhos) msg = "Spectrum incorrect for free spectrum." assert np.all(rnm.get_phi(params) == phi), msg # inverse spectrum test msg = "Spectrum inverse incorrect for free spectrum." assert np.all(rnm.get_phiinv(params) == 1 / phi), msg # test shape msg = "F matrix shape incorrect" assert rnm.get_basis(params).shape == F.shape, msg
def gwb(self,option="hd_vary_gamma"): """ Spatially-correlated quadrupole signal from the nanohertz stochastic gravitational-wave background. """ name = 'gw' if "_nfreqs" in option: split_idx_nfreqs = option.split('_').index('nfreqs') - 1 nfreqs = int(option.split('_')[split_idx_nfreqs]) else: nfreqs = self.determine_nfreqs(sel_func_name=None, common_signal=True) if "_gamma" in option: amp_name = '{}_log10_A'.format(name) if self.params.gwb_lgA_prior == "uniform": gwb_log10_A = parameter.Uniform(self.params.gwb_lgA[0], self.params.gwb_lgA[1])(amp_name) elif self.params.gwb_lgA_prior == "linexp": gwb_log10_A = parameter.LinearExp(self.params.gwb_lgA[0], self.params.gwb_lgA[1])(amp_name) gam_name = '{}_gamma'.format(name) if "vary_gamma" in option: gwb_gamma = parameter.Uniform(self.params.gwb_gamma[0], self.params.gwb_gamma[1])(gam_name) elif "fixed_gamma" in option: gwb_gamma = parameter.Constant(4.33)(gam_name) else: split_idx_gamma = option.split('_').index('gamma') - 1 gamma_val = float(option.split('_')[split_idx_gamma]) gwb_gamma = parameter.Constant(gamma_val)(gam_name) gwb_pl = utils.powerlaw(log10_A=gwb_log10_A, gamma=gwb_gamma) elif "freesp" in option: amp_name = '{}_log10_rho'.format(name) log10_rho = parameter.Uniform(self.params.gwb_lgrho[0], self.params.gwb_lgrho[1], size=nfreqs)(amp_name) gwb_pl = gp_priors.free_spectrum(log10_rho=log10_rho) if "hd" in option: orf = utils.hd_orf() gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name='gwb', Tspan=self.params.Tspan) else: gwb = gp_signals.FourierBasisGP(gwb_pl, components=nfreqs, name='gwb', Tspan=self.params.Tspan) return gwb
# timing model s = gp_signals.MarginalizingTimingModel() s += blocks.white_noise_block(vary=False, inc_ecorr=True, select='backend') s += blocks.red_noise_block( psd='powerlaw', prior='log-uniform', Tspan=Tspan_PTA, modes=modes, wgts=wgts, ) log10_rho_gw = parameter.Uniform(-9, -2, size=19)('gw_crn_log10_rho') cpl = gpp.free_spectrum(log10_rho=log10_rho_gw) s += gp_signals.FourierBasisGP(cpl, modes=modes, name='gw_crn') # gw = blocks.common_red_noise_block(psd='powerlaw', prior='log-uniform', Tspan=Tspan_PTA, # components=5, gamma_val=4.33, name='gw', orf='hd') crn_models = [s(psr) for psr in pkl_psrs] # gw_models = [(m + gw)(psr) for psr,m in zip(final_psrs,psr_models)] pta_crn = signal_base.PTA(crn_models) # pta_gw = signal_base.PTA(gw_models) # # delta_common=0., # ptas = {0:pta_crn, # 1:pta_gw}
def common_red_noise_block(psd='powerlaw', prior='log-uniform', Tspan=None, components=30, log10_A_val=None, gamma_val=None, delta_val=None, orf=None, orf_ifreq=0, leg_lmax=5, name='gw', coefficients=False, pshift=False, pseed=None): """ Returns common red noise model: 1. Red noise modeled with user defined PSD with 30 sampling frequencies. Available PSDs are ['powerlaw', 'turnover' 'spectrum'] :param psd: PSD to use for common red noise signal. Available options are ['powerlaw', 'turnover' 'spectrum', 'broken_powerlaw'] :param prior: Prior on log10_A. Default if "log-uniform". Use "uniform" for upper limits. :param Tspan: Sets frequency sampling f_i = i / Tspan. Default will use overall time span for individual pulsar. :param log10_A_val: Value of log10_A parameter for fixed amplitude analyses. :param gamma_val: Value of spectral index for power-law and turnover models. By default spectral index is varied of range [0,7] :param delta_val: Value of spectral index for high frequencies in broken power-law and turnover models. By default spectral index is varied in range [0,7]. :param orf: String representing which overlap reduction function to use. By default we do not use any spatial correlations. Permitted values are ['hd', 'dipole', 'monopole']. :param orf_ifreq: Frequency bin at which to start the Hellings & Downs function with numbering beginning at 0. Currently only works with freq_hd orf. :param leg_lmax: Maximum multipole of a Legendre polynomial series representation of the overlap reduction function [default=5] :param pshift: Option to use a random phase shift in design matrix. For testing the null hypothesis. :param pseed: Option to provide a seed for the random phase shift. :param name: Name of common red process """ orfs = { 'crn': None, 'hd': utils.hd_orf(), 'dipole': utils.dipole_orf(), 'monopole': utils.monopole_orf(), 'param_hd': model_orfs.param_hd_orf(a=parameter.Uniform(-1.5, 3.0)('gw_orf_param0'), b=parameter.Uniform(-1.0, 0.5)('gw_orf_param1'), c=parameter.Uniform(-1.0, 1.0)('gw_orf_param2')), 'spline_orf': model_orfs.spline_orf( params=parameter.Uniform(-0.9, 0.9, size=7)('gw_orf_spline')), 'bin_orf': model_orfs.bin_orf( params=parameter.Uniform(-1.0, 1.0, size=7)('gw_orf_bin')), 'zero_diag_hd': model_orfs.zero_diag_hd(), 'zero_diag_bin_orf': model_orfs.zero_diag_bin_orf(params=parameter.Uniform( -1.0, 1.0, size=7)('gw_orf_bin_zero_diag')), 'freq_hd': model_orfs.freq_hd(params=[components, orf_ifreq]), 'legendre_orf': model_orfs.legendre_orf( params=parameter.Uniform(-1.0, 1.0, size=leg_lmax + 1)('gw_orf_legendre')), 'zero_diag_legendre_orf': model_orfs.zero_diag_legendre_orf( params=parameter.Uniform(-1.0, 1.0, size=leg_lmax + 1)('gw_orf_legendre_zero_diag')) } # common red noise parameters if psd in ['powerlaw', 'turnover', 'turnover_knee', 'broken_powerlaw']: amp_name = '{}_log10_A'.format(name) if log10_A_val is not None: log10_Agw = parameter.Constant(log10_A_val)(amp_name) else: if prior == 'uniform': log10_Agw = parameter.LinearExp(-18, -11)(amp_name) elif prior == 'log-uniform' and gamma_val is not None: if np.abs(gamma_val - 4.33) < 0.1: log10_Agw = parameter.Uniform(-18, -14)(amp_name) else: log10_Agw = parameter.Uniform(-18, -11)(amp_name) else: log10_Agw = parameter.Uniform(-18, -11)(amp_name) gam_name = '{}_gamma'.format(name) if gamma_val is not None: gamma_gw = parameter.Constant(gamma_val)(gam_name) else: gamma_gw = parameter.Uniform(0, 7)(gam_name) # common red noise PSD if psd == 'powerlaw': cpl = utils.powerlaw(log10_A=log10_Agw, gamma=gamma_gw) elif psd == 'broken_powerlaw': delta_name = '{}_delta'.format(name) kappa_name = '{}_kappa'.format(name) log10_fb_name = '{}_log10_fb'.format(name) kappa_gw = parameter.Uniform(0.01, 0.5)(kappa_name) log10_fb_gw = parameter.Uniform(-10, -7)(log10_fb_name) if delta_val is not None: delta_gw = parameter.Constant(delta_val)(delta_name) else: delta_gw = parameter.Uniform(0, 7)(delta_name) cpl = gpp.broken_powerlaw(log10_A=log10_Agw, gamma=gamma_gw, delta=delta_gw, log10_fb=log10_fb_gw, kappa=kappa_gw) elif psd == 'turnover': kappa_name = '{}_kappa'.format(name) lf0_name = '{}_log10_fbend'.format(name) kappa_gw = parameter.Uniform(0, 7)(kappa_name) lf0_gw = parameter.Uniform(-9, -7)(lf0_name) cpl = utils.turnover(log10_A=log10_Agw, gamma=gamma_gw, lf0=lf0_gw, kappa=kappa_gw) elif psd == 'turnover_knee': kappa_name = '{}_kappa'.format(name) lfb_name = '{}_log10_fbend'.format(name) delta_name = '{}_delta'.format(name) lfk_name = '{}_log10_fknee'.format(name) kappa_gw = parameter.Uniform(0, 7)(kappa_name) lfb_gw = parameter.Uniform(-9.3, -8)(lfb_name) delta_gw = parameter.Uniform(-2, 0)(delta_name) lfk_gw = parameter.Uniform(-8, -7)(lfk_name) cpl = gpp.turnover_knee(log10_A=log10_Agw, gamma=gamma_gw, lfb=lfb_gw, lfk=lfk_gw, kappa=kappa_gw, delta=delta_gw) if psd == 'spectrum': rho_name = '{}_log10_rho'.format(name) if prior == 'uniform': log10_rho_gw = parameter.LinearExp(-9, -4, size=components)(rho_name) elif prior == 'log-uniform': log10_rho_gw = parameter.Uniform(-9, -4, size=components)(rho_name) cpl = gpp.free_spectrum(log10_rho=log10_rho_gw) if orf is None: crn = gp_signals.FourierBasisGP(cpl, coefficients=coefficients, components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) elif orf in orfs.keys(): if orf == 'crn': crn = gp_signals.FourierBasisGP(cpl, coefficients=coefficients, components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) else: crn = gp_signals.FourierBasisCommonGP(cpl, orfs[orf], components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) elif isinstance(orf, types.FunctionType): crn = gp_signals.FourierBasisCommonGP(cpl, orf, components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) else: raise ValueError('ORF {} not recognized'.format(orf)) return crn
def chromatic_noise_block(gp_kernel='nondiag', psd='powerlaw', nondiag_kernel='periodic', prior='log-uniform', dt=15, df=200, idx=4, include_quadratic=False, Tspan=None, name='chrom', components=30, coefficients=False): """ Returns GP chromatic noise model : 1. Chromatic modeled with user defined PSD with 30 sampling frequencies. Available PSDs are ['powerlaw', 'turnover' 'spectrum'] :param gp_kernel: Whether to use a diagonal kernel for the GP. ['diag','nondiag'] :param nondiag_kernel: Which nondiagonal kernel to use for the GP. ['periodic','sq_exp','periodic_rfband','sq_exp_rfband'] :param psd: PSD to use for common red noise signal. Available options are ['powerlaw', 'turnover' 'spectrum'] :param prior: What type of prior to use for amplitudes. ['log-uniform','uniform'] :param dt: time-scale for linear interpolation basis (days) :param df: frequency-scale for linear interpolation basis (MHz) :param idx: Index of radio frequency dependence (i.e. DM is 2). Any float will work. :param include_quadratic: Whether to include a quadratic fit. :param name: Name of signal :param Tspan: Tspan from which to calculate frequencies for PSD-based GPs. :param components: Number of frequencies to use in 'diag' GPs. :param coefficients: Whether to keep coefficients of the GP. """ if gp_kernel == 'diag': chm_basis = gpb.createfourierdesignmatrix_chromatic(nmodes=components, Tspan=Tspan) if psd in ['powerlaw', 'turnover']: if prior == 'uniform': log10_A = parameter.LinearExp(-18, -11) elif prior == 'log-uniform': log10_A = parameter.Uniform(-18, -11) gamma = parameter.Uniform(0, 7) # PSD if psd == 'powerlaw': chm_prior = utils.powerlaw(log10_A=log10_A, gamma=gamma) elif psd == 'turnover': kappa = parameter.Uniform(0, 7) lf0 = parameter.Uniform(-9, -7) chm_prior = utils.turnover(log10_A=log10_A, gamma=gamma, lf0=lf0, kappa=kappa) if psd == 'spectrum': if prior == 'uniform': log10_rho = parameter.LinearExp(-10, -4, size=components) elif prior == 'log-uniform': log10_rho = parameter.Uniform(-10, -4, size=components) chm_prior = gpp.free_spectrum(log10_rho=log10_rho) elif gp_kernel == 'nondiag': if nondiag_kernel == 'periodic': # Periodic GP kernel for DM log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) log10_p = parameter.Uniform(-4, 1) log10_gam_p = parameter.Uniform(-3, 2) chm_basis = gpk.linear_interp_basis_chromatic(dt=dt * const.day) chm_prior = gpk.periodic_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell, log10_gam_p=log10_gam_p, log10_p=log10_p) elif nondiag_kernel == 'periodic_rfband': # Periodic GP kernel for DM with RQ radio-frequency dependence log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) log10_ell2 = parameter.Uniform(2, 7) log10_alpha_wgt = parameter.Uniform(-4, 1) log10_p = parameter.Uniform(-4, 1) log10_gam_p = parameter.Uniform(-3, 2) chm_basis = gpk.get_tf_quantization_matrix(df=df, dt=dt * const.day, dm=True, idx=idx) chm_prior = gpk.tf_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell, log10_gam_p=log10_gam_p, log10_p=log10_p, log10_alpha_wgt=log10_alpha_wgt, log10_ell2=log10_ell2) elif nondiag_kernel == 'sq_exp': # squared-exponential kernel for DM log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) chm_basis = gpk.linear_interp_basis_chromatic(dt=dt * const.day, idx=idx) chm_prior = gpk.se_dm_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell) elif nondiag_kernel == 'sq_exp_rfband': # Sq-Exp GP kernel for Chrom with RQ radio-frequency dependence log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) log10_ell2 = parameter.Uniform(2, 7) log10_alpha_wgt = parameter.Uniform(-4, 1) dm_basis = gpk.get_tf_quantization_matrix(df=df, dt=dt * const.day, dm=True, idx=idx) dm_prior = gpk.sf_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell, log10_alpha_wgt=log10_alpha_wgt, log10_ell2=log10_ell2) cgp = gp_signals.BasisGP(chm_prior, chm_basis, name=name + '_gp', coefficients=coefficients) if include_quadratic: # quadratic piece basis_quad = chrom.chromatic_quad_basis(idx=idx) prior_quad = chrom.chromatic_quad_prior() cquad = gp_signals.BasisGP(prior_quad, basis_quad, name=name + '_quad') cgp += cquad return cgp
def dm_noise_block(gp_kernel='diag', psd='powerlaw', nondiag_kernel='periodic', prior='log-uniform', dt=15, df=200, Tspan=None, components=30, gamma_val=None, coefficients=False): """ Returns DM noise model: 1. DM noise modeled as a power-law with 30 sampling frequencies :param psd: PSD function [e.g. powerlaw (default), spectrum, tprocess] :param prior: Prior on log10_A. Default if "log-uniform". Use "uniform" for upper limits. :param dt: time-scale for linear interpolation basis (days) :param df: frequency-scale for linear interpolation basis (MHz) :param Tspan: Sets frequency sampling f_i = i / Tspan. Default will use overall time span for indivicual pulsar. :param components: Number of frequencies in sampling of DM-variations. :param gamma_val: If given, this is the fixed slope of the power-law for powerlaw, turnover, or tprocess DM-variations """ # dm noise parameters that are common if gp_kernel == 'diag': if psd in ['powerlaw', 'turnover', 'tprocess', 'tprocess_adapt']: # parameters shared by PSD functions if prior == 'uniform': log10_A_dm = parameter.LinearExp(-20, -11) elif prior == 'log-uniform' and gamma_val is not None: if np.abs(gamma_val - 4.33) < 0.1: log10_A_dm = parameter.Uniform(-20, -11) else: log10_A_dm = parameter.Uniform(-20, -11) else: log10_A_dm = parameter.Uniform(-20, -11) if gamma_val is not None: gamma_dm = parameter.Constant(gamma_val) else: gamma_dm = parameter.Uniform(0, 7) # different PSD function parameters if psd == 'powerlaw': dm_prior = utils.powerlaw(log10_A=log10_A_dm, gamma=gamma_dm) elif psd == 'turnover': kappa_dm = parameter.Uniform(0, 7) lf0_dm = parameter.Uniform(-9, -7) dm_prior = utils.turnover(log10_A=log10_A_dm, gamma=gamma_dm, lf0=lf0_dm, kappa=kappa_dm) elif psd == 'tprocess': df = 2 alphas_dm = gpp.InvGamma(df / 2, df / 2, size=components) dm_prior = gpp.t_process(log10_A=log10_A_dm, gamma=gamma_dm, alphas=alphas_dm) elif psd == 'tprocess_adapt': df = 2 alpha_adapt_dm = gpp.InvGamma(df / 2, df / 2, size=1) nfreq_dm = parameter.Uniform(-0.5, 10 - 0.5) dm_prior = gpp.t_process_adapt(log10_A=log10_A_dm, gamma=gamma_dm, alphas_adapt=alpha_adapt_dm, nfreq=nfreq_dm) if psd == 'spectrum': if prior == 'uniform': log10_rho_dm = parameter.LinearExp(-10, -4, size=components) elif prior == 'log-uniform': log10_rho_dm = parameter.Uniform(-10, -4, size=components) dm_prior = gpp.free_spectrum(log10_rho=log10_rho_dm) dm_basis = utils.createfourierdesignmatrix_dm(nmodes=components, Tspan=Tspan) elif gp_kernel == 'nondiag': if nondiag_kernel == 'periodic': # Periodic GP kernel for DM log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) log10_p = parameter.Uniform(-4, 1) log10_gam_p = parameter.Uniform(-3, 2) dm_basis = gpk.linear_interp_basis_dm(dt=dt * const.day) dm_prior = gpk.periodic_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell, log10_gam_p=log10_gam_p, log10_p=log10_p) elif nondiag_kernel == 'periodic_rfband': # Periodic GP kernel for DM with RQ radio-frequency dependence log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) log10_ell2 = parameter.Uniform(2, 7) log10_alpha_wgt = parameter.Uniform(-4, 1) log10_p = parameter.Uniform(-4, 1) log10_gam_p = parameter.Uniform(-3, 2) dm_basis = gpk.get_tf_quantization_matrix(df=df, dt=dt * const.day, dm=True) dm_prior = gpk.tf_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell, log10_gam_p=log10_gam_p, log10_p=log10_p, log10_alpha_wgt=log10_alpha_wgt, log10_ell2=log10_ell2) elif nondiag_kernel == 'sq_exp': # squared-exponential GP kernel for DM log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) dm_basis = gpk.linear_interp_basis_dm(dt=dt * const.day) dm_prior = gpk.se_dm_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell) elif nondiag_kernel == 'sq_exp_rfband': # Sq-Exp GP kernel for DM with RQ radio-frequency dependence log10_sigma = parameter.Uniform(-10, -4) log10_ell = parameter.Uniform(1, 4) log10_ell2 = parameter.Uniform(2, 7) log10_alpha_wgt = parameter.Uniform(-4, 1) dm_basis = gpk.get_tf_quantization_matrix(df=df, dt=dt * const.day, dm=True) dm_prior = gpk.sf_kernel(log10_sigma=log10_sigma, log10_ell=log10_ell, log10_alpha_wgt=log10_alpha_wgt, log10_ell2=log10_ell2) elif nondiag_kernel == 'dmx_like': # DMX-like signal log10_sigma = parameter.Uniform(-10, -4) dm_basis = gpk.linear_interp_basis_dm(dt=dt * const.day) dm_prior = gpk.dmx_ridge_prior(log10_sigma=log10_sigma) dmgp = gp_signals.BasisGP(dm_prior, dm_basis, name='dm_gp', coefficients=coefficients) return dmgp
def red_noise_block(psd='powerlaw', prior='log-uniform', Tspan=None, components=30, gamma_val=None, coefficients=False, select=None, modes=None, wgts=None, break_flat=False, break_flat_fq=None): """ Returns red noise model: 1. Red noise modeled as a power-law with 30 sampling frequencies :param psd: PSD function [e.g. powerlaw (default), turnover, spectrum, tprocess] :param prior: Prior on log10_A. Default if "log-uniform". Use "uniform" for upper limits. :param Tspan: Sets frequency sampling f_i = i / Tspan. Default will use overall time span for indivicual pulsar. :param components: Number of frequencies in sampling of red noise :param gamma_val: If given, this is the fixed slope of the power-law for powerlaw, turnover, or tprocess red noise :param coefficients: include latent coefficients in GP model? """ # red noise parameters that are common if psd in [ 'powerlaw', 'powerlaw_genmodes', 'turnover', 'tprocess', 'tprocess_adapt', 'infinitepower' ]: # parameters shared by PSD functions if prior == 'uniform': log10_A = parameter.LinearExp(-20, -11) elif prior == 'log-uniform' and gamma_val is not None: if np.abs(gamma_val - 4.33) < 0.1: log10_A = parameter.Uniform(-20, -11) else: log10_A = parameter.Uniform(-20, -11) else: log10_A = parameter.Uniform(-20, -11) if gamma_val is not None: gamma = parameter.Constant(gamma_val) else: gamma = parameter.Uniform(0, 7) # different PSD function parameters if psd == 'powerlaw': pl = utils.powerlaw(log10_A=log10_A, gamma=gamma) elif psd == 'powerlaw_genmodes': pl = gpp.powerlaw_genmodes(log10_A=log10_A, gamma=gamma, wgts=wgts) elif psd == 'turnover': kappa = parameter.Uniform(0, 7) lf0 = parameter.Uniform(-9, -7) pl = utils.turnover(log10_A=log10_A, gamma=gamma, lf0=lf0, kappa=kappa) elif psd == 'tprocess': df = 2 alphas = gpp.InvGamma(df / 2, df / 2, size=components) pl = gpp.t_process(log10_A=log10_A, gamma=gamma, alphas=alphas) elif psd == 'tprocess_adapt': df = 2 alpha_adapt = gpp.InvGamma(df / 2, df / 2, size=1) nfreq = parameter.Uniform(-0.5, 10 - 0.5) pl = gpp.t_process_adapt(log10_A=log10_A, gamma=gamma, alphas_adapt=alpha_adapt, nfreq=nfreq) elif psd == 'infinitepower': pl = gpp.infinitepower() if psd == 'spectrum': if prior == 'uniform': log10_rho = parameter.LinearExp(-10, -4, size=components) elif prior == 'log-uniform': log10_rho = parameter.Uniform(-10, -4, size=components) pl = gpp.free_spectrum(log10_rho=log10_rho) if select == 'backend': # define selection by observing backend selection = selections.Selection(selections.by_backend) elif select == 'band' or select == 'band+': # define selection by observing band selection = selections.Selection(selections.by_band) else: # define no selection selection = selections.Selection(selections.no_selection) if break_flat: log10_A_flat = parameter.Uniform(-20, -11) gamma_flat = parameter.Constant(0) pl_flat = utils.powerlaw(log10_A=log10_A_flat, gamma=gamma_flat) freqs = 1.0 * np.arange(1, components + 1) / Tspan components_low = sum(f < break_flat_fq for f in freqs) if components_low < 1.5: components_low = 2 rn = gp_signals.FourierBasisGP(pl, components=components_low, Tspan=Tspan, coefficients=coefficients, selection=selection) rn_flat = gp_signals.FourierBasisGP(pl_flat, modes=freqs[components_low:], coefficients=coefficients, selection=selection, name='red_noise_hf') rn = rn + rn_flat else: rn = gp_signals.FourierBasisGP(pl, components=components, Tspan=Tspan, coefficients=coefficients, selection=selection, modes=modes) if select == 'band+': # Add the common component as well rn = rn + gp_signals.FourierBasisGP( pl, components=components, Tspan=Tspan, coefficients=coefficients) return rn
def gwb(self,option="hd_vary_gamma"): """ Spatially-correlated quadrupole signal from the nanohertz stochastic gravitational-wave background. """ name = 'gw' optsp = option.split('+') for option in optsp: if "_nfreqs" in option: split_idx_nfreqs = option.split('_').index('nfreqs') - 1 nfreqs = int(option.split('_')[split_idx_nfreqs]) else: nfreqs = self.determine_nfreqs(sel_func_name=None, common_signal=True) print('Number of Fourier frequencies for the GWB/CPL signal: ', nfreqs) if "_gamma" in option: amp_name = '{}_log10_A'.format(name) if (len(optsp) > 1 and 'hd' in option) or ('namehd' in option): amp_name += '_hd' elif (len(optsp) > 1 and ('varorf' in option or \ 'interporf' in option)) \ or ('nameorf' in option): amp_name += '_orf' if self.params.gwb_lgA_prior == "uniform": gwb_log10_A = parameter.Uniform(self.params.gwb_lgA[0], self.params.gwb_lgA[1])(amp_name) elif self.params.gwb_lgA_prior == "linexp": gwb_log10_A = parameter.LinearExp(self.params.gwb_lgA[0], self.params.gwb_lgA[1])(amp_name) gam_name = '{}_gamma'.format(name) if "vary_gamma" in option: gwb_gamma = parameter.Uniform(self.params.gwb_gamma[0], self.params.gwb_gamma[1])(gam_name) elif "fixed_gamma" in option: gwb_gamma = parameter.Constant(4.33)(gam_name) else: split_idx_gamma = option.split('_').index('gamma') - 1 gamma_val = float(option.split('_')[split_idx_gamma]) gwb_gamma = parameter.Constant(gamma_val)(gam_name) gwb_pl = utils.powerlaw(log10_A=gwb_log10_A, gamma=gwb_gamma) elif "freesp" in option: amp_name = '{}_log10_rho'.format(name) log10_rho = parameter.Uniform(self.params.gwb_lgrho[0], self.params.gwb_lgrho[1], size=nfreqs)(amp_name) gwb_pl = gp_priors.free_spectrum(log10_rho=log10_rho) if "hd" in option: print('Adding HD ORF') if "noauto" in option: print('Removing auto-correlation') orf = hd_orf_noauto() else: orf = utils.hd_orf() if len(optsp) > 1 or 'namehd' in option: gwname = 'gw_hd' else: gwname = 'gw' gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name=gwname, Tspan=self.params.Tspan) elif "mono" in option: print('Adding monopole ORF') orf = utils.monopole_orf() gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name='gw', Tspan=self.params.Tspan) elif "dipo" in option: print('Adding dipole ORF') orf = utils.dipole_orf() gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name='gw', Tspan=self.params.Tspan) else: gwb = gp_signals.FourierBasisGP(gwb_pl, components=nfreqs, name='gw', Tspan=self.params.Tspan) if 'gw_total' in locals(): gwb_total += gwb else: gwb_total = gwb return gwb_total
def compute_os(self, params=None, psd='powerlaw', fgw=None): """ Computes the optimal statistic values given an `enterprise` parameter dictionary. :param params: `enterprise` parameter dictionary. :param psd: choice of cross-power psd [powerlaw,spectrum] :fgw: frequency of GW spectrum to probe, in Hz [default=None] :returns: xi: angular separation [rad] for each pulsar pair rho: correlation coefficient for each pulsar pair sig: 1-sigma uncertainty on correlation coefficient for each pulsar pair. OS: Optimal statistic value (units of A_gw^2) OS_sig: 1-sigma uncertainty on OS .. note:: SNR is computed as OS / OS_sig. In the case of a 'spectrum' model the OS variable will be the PSD(fgw) * Tspan value at the relevant fgw bin. """ if params is None: params = {name: par.sample() for name, par in zip(self.pta.param_names, self.pta.params)} else: # check to see that the params dictionary includes values # for all of the parameters in the model for p in self.pta.param_names: if p not in params.keys(): msg = '{0} is not included '.format(p) msg += 'in the parameter dictionary. ' msg += 'Drawing a random value.' warnings.warn(msg); # get matrix products TNrs = self.get_TNr(params=params) TNTs = self.get_TNT(params=params) FNrs = self.get_FNr(params=params) FNFs = self.get_FNF(params=params) FNTs = self.get_FNT(params=params) phiinvs = self.pta.get_phiinv(params, logdet=False) X, Z = [], [] for TNr, TNT, FNr, FNF, FNT, phiinv in zip(TNrs, TNTs, FNrs, FNFs, FNTs, phiinvs): Sigma = TNT + (np.diag(phiinv) if phiinv.ndim == 1 else phiinv) try: cf = sl.cho_factor(Sigma) SigmaTNr = sl.cho_solve(cf, TNr) SigmaTNF = sl.cho_solve(cf, FNT.T) except np.linalg.LinAlgError: SigmaTNr = np.linalg.solve(Sigma, TNr) SigmaTNF = np.linalg.solve(Sigma, FNT.T) FNTSigmaTNr = np.dot(FNT, SigmaTNr) X.append(FNr - FNTSigmaTNr) Z.append(FNF - np.dot(FNT, SigmaTNF)) npsr = len(self.pta._signalcollections) rho, sig, ORF, xi = [], [], [], [] for ii in range(npsr): for jj in range(ii+1, npsr): if psd == 'powerlaw': if self.gamma_common is None and 'gw_gamma' in params.keys(): print('{0:1.2}'.format(params['gw_gamma'])) phiIJ = utils.powerlaw(self.freqs, log10_A=0, gamma=params['gw_gamma']) else: phiIJ = utils.powerlaw(self.freqs, log10_A=0, gamma=self.gamma_common) elif psd == 'spectrum': Sf = -np.inf * np.ones(int(len(self.freqs)/2)) idx = (np.abs(np.unique(self.freqs) - fgw)).argmin() Sf[idx] = 0.0 phiIJ = gp_priors.free_spectrum(self.freqs, log10_rho=Sf) top = np.dot(X[ii], phiIJ * X[jj]) bot = np.trace(np.dot(Z[ii]*phiIJ[None,:], Z[jj]*phiIJ[None,:])) # cross correlation and uncertainty rho.append(top / bot) sig.append(1 / np.sqrt(bot)) # Overlap reduction function for PSRs ii, jj ORF.append(self.orf(self.psrlocs[ii], self.psrlocs[jj])) # angular separation xi.append(np.arccos(np.dot(self.psrlocs[ii], self.psrlocs[jj]))) rho = np.array(rho) sig = np.array(sig) ORF = np.array(ORF) xi = np.array(xi) OS = (np.sum(rho*ORF / sig ** 2) / np.sum(ORF ** 2 / sig ** 2)) OS_sig = 1 / np.sqrt(np.sum(ORF ** 2 / sig ** 2)) return xi, rho, sig, OS, OS_sig
def common_red_noise_block(psd='powerlaw', prior='log-uniform', Tspan=None, components=30, gamma_val=None, orf=None, name='gw', coefficients=False, pshift=False, pseed=None): """ Returns common red noise model: 1. Red noise modeled with user defined PSD with 30 sampling frequencies. Available PSDs are ['powerlaw', 'turnover' 'spectrum'] :param psd: PSD to use for common red noise signal. Available options are ['powerlaw', 'turnover' 'spectrum'] :param prior: Prior on log10_A. Default if "log-uniform". Use "uniform" for upper limits. :param Tspan: Sets frequency sampling f_i = i / Tspan. Default will use overall time span for indivicual pulsar. :param gamma_val: Value of spectral index for power-law and turnover models. By default spectral index is varied of range [0,7] :param orf: String representing which overlap reduction function to use. By default we do not use any spatial correlations. Permitted values are ['hd', 'dipole', 'monopole']. :param pshift: Option to use a random phase shift in design matrix. For testing the null hypothesis. :param pseed: Option to provide a seed for the random phase shift. :param name: Name of common red process """ orfs = { 'hd': utils.hd_orf(), 'dipole': utils.dipole_orf(), 'monopole': utils.monopole_orf() } # common red noise parameters if psd in ['powerlaw', 'turnover', 'turnover_knee']: amp_name = '{}_log10_A'.format(name) if prior == 'uniform': log10_Agw = parameter.LinearExp(-18, -11)(amp_name) elif prior == 'log-uniform' and gamma_val is not None: if np.abs(gamma_val - 4.33) < 0.1: log10_Agw = parameter.Uniform(-18, -14)(amp_name) else: log10_Agw = parameter.Uniform(-18, -11)(amp_name) else: log10_Agw = parameter.Uniform(-18, -11)(amp_name) gam_name = '{}_gamma'.format(name) if gamma_val is not None: gamma_gw = parameter.Constant(gamma_val)(gam_name) else: gamma_gw = parameter.Uniform(0, 7)(gam_name) # common red noise PSD if psd == 'powerlaw': cpl = utils.powerlaw(log10_A=log10_Agw, gamma=gamma_gw) elif psd == 'turnover': kappa_name = '{}_kappa'.format(name) lf0_name = '{}_log10_fbend'.format(name) kappa_gw = parameter.Uniform(0, 7)(kappa_name) lf0_gw = parameter.Uniform(-9, -7)(lf0_name) cpl = utils.turnover(log10_A=log10_Agw, gamma=gamma_gw, lf0=lf0_gw, kappa=kappa_gw) elif psd == 'turnover_knee': kappa_name = '{}_kappa'.format(name) lfb_name = '{}_log10_fbend'.format(name) delta_name = '{}_delta'.format(name) lfk_name = '{}_log10_fknee'.format(name) kappa_gw = parameter.Uniform(0, 7)(kappa_name) lfb_gw = parameter.Uniform(-9.3, -8)(lfb_name) delta_gw = parameter.Uniform(-2, 0)(delta_name) lfk_gw = parameter.Uniform(-8, -7)(lfk_name) cpl = gpp.turnover_knee(log10_A=log10_Agw, gamma=gamma_gw, lfb=lfb_gw, lfk=lfk_gw, kappa=kappa_gw, delta=delta_gw) if psd == 'spectrum': rho_name = '{}_log10_rho'.format(name) if prior == 'uniform': log10_rho_gw = parameter.LinearExp(-9, -4, size=components)(rho_name) elif prior == 'log-uniform': log10_rho_gw = parameter.Uniform(-9, -4, size=components)(rho_name) cpl = gpp.free_spectrum(log10_rho=log10_rho_gw) if orf is None: crn = gp_signals.FourierBasisGP(cpl, coefficients=coefficients, components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) elif orf in orfs.keys(): crn = gp_signals.FourierBasisCommonGP(cpl, orfs[orf], components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) elif isinstance(orf, types.FunctionType): crn = gp_signals.FourierBasisCommonGP(cpl, orf, components=components, Tspan=Tspan, name=name, pshift=pshift, pseed=pseed) else: raise ValueError('ORF {} not recognized'.format(orf)) return crn
def gwb(self,option="hd_vary_gamma"): """ Spatially-correlated quadrupole signal from the nanohertz stochastic gravitational-wave background. """ name = 'gw' optsp = option.split('+') for option in optsp: if "_nfreqs" in option: split_idx_nfreqs = option.split('_').index('nfreqs') - 1 nfreqs = int(option.split('_')[split_idx_nfreqs]) else: nfreqs = self.determine_nfreqs(sel_func_name=None, common_signal=True) print('Number of Fourier frequencies for the GWB/CPL signal: ', nfreqs) if "_gamma" in option: amp_name = '{}_log10_A'.format(name) if (len(optsp) > 1 and 'hd' in option) or ('namehd' in option): amp_name += '_hd' elif (len(optsp) > 1 and ('varorf' in option or \ 'interporf' in option)) \ or ('nameorf' in option): amp_name += '_orf' if self.params.gwb_lgA_prior == "uniform": gwb_log10_A = parameter.Uniform(self.params.gwb_lgA[0], self.params.gwb_lgA[1])(amp_name) elif self.params.gwb_lgA_prior == "linexp": gwb_log10_A = parameter.LinearExp(self.params.gwb_lgA[0], self.params.gwb_lgA[1])(amp_name) elif self.params.gwb_lgA_prior == "normal": gwb_log10_A = parameter.Normal(mu=self.params.gwb_lgA[0], sigma=self.params.gwb_lgA[1])(amp_name) gam_name = '{}_gamma'.format(name) if "vary_gamma" in option: if self.params.gwb_gamma_prior == "uniform": gwb_gamma = parameter.Uniform(self.params.gwb_gamma[0], self.params.gwb_gamma[1])(gam_name) if self.params.gwb_gamma_prior == "normal": gwb_gamma = parameter.Normal(sigma=self.params.gwb_gamma[1], mu=self.params.gwb_gamma[0])(gam_name) elif "fixed_gamma" in option: gwb_gamma = parameter.Constant(4.33)(gam_name) else: split_idx_gamma = option.split('_').index('gamma') - 1 gamma_val = float(option.split('_')[split_idx_gamma]) gwb_gamma = parameter.Constant(gamma_val)(gam_name) gwb_pl = utils.powerlaw(log10_A=gwb_log10_A, gamma=gwb_gamma) elif "freesp" in option: amp_name = '{}_log10_rho'.format(name) log10_rho = parameter.Uniform(self.params.gwb_lgrho[0], self.params.gwb_lgrho[1], size=nfreqs)(amp_name) gwb_pl = gp_priors.free_spectrum(log10_rho=log10_rho) if "hd" in option: print('Adding HD ORF') if "noauto" in option: print('Removing auto-correlation') orf = hd_orf_noauto() else: import time print('AZ about to do hd orf', time.perf_counter()) orf = utils.hd_orf() print('AZ called utils.hd_orf', time.perf_counter()) if len(optsp) > 1 or 'namehd' in option: gwname = 'gwb_hd' else: gwname = 'gwb' #print('evaluating gwb fourierbasiscommongp', time.perf_counter()) gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name=gwname, Tspan=self.params.Tspan) #print('evaluating gwb fourierbasiscommongp', time.perf_counter()) elif "mono" in option: print('Adding monopole ORF') orf = utils.monopole_orf() gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name='gwb', Tspan=self.params.Tspan) elif "dipo" in option: print('Adding dipole ORF') orf = utils.dipole_orf() gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name='gwb', Tspan=self.params.Tspan) elif "halfdip" in option: print('Adding dipole/2 ORF') orf = halfdip_orf() gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name='gwb', Tspan=self.params.Tspan) elif "varorf" in option: if len(optsp) > 1 or 'nameorf' in option: gwname = 'gwb_orf' else: gwname = 'gwb' corr_coeff = parameter.Uniform(-1., 1., size=7)('corr_coeff') if "noauto" in option: orf = infer_orf_noauto(corr_coeff=corr_coeff) else: orf = infer_orf(corr_coeff=corr_coeff) gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name=gwname, Tspan=self.params.Tspan) elif "interporf" in option: print("Adding numpy-interpolated free ORF") if len(optsp) > 1 or 'nameorf' in option: gwname = 'gwb_orf' else: gwname = 'gwb' corr_coeff = parameter.Uniform(-1., 1., size=7)('corr_coeff') if "noauto" in option: orf = infer_orf_npinterp_noauto(corr_coeff=corr_coeff) else: orf = infer_orf_npinterp(corr_coeff=corr_coeff) if "skyscr" in option: gwb = FourierBasisSkyscrambledGP(gwb_pl, orf, components=nfreqs, name=gwname+'_skyscr', Tspan=self.params.Tspan) else: gwb = gp_signals.FourierBasisCommonGP(gwb_pl, orf, components=nfreqs, name=gwname, Tspan=self.params.Tspan) else: gwb = gp_signals.FourierBasisGP(gwb_pl, components=nfreqs, name='gwb', Tspan=self.params.Tspan) if 'gwb_total' in locals(): gwb_total += gwb else: gwb_total = gwb return gwb_total
with open(args.pickle, 'rb') as fin: psrs = pickle.load(fin) psr = psrs[args.process] print(f'Starting {psr.name}.') with open(args.noisepath, 'r') as fin: noise = json.load(fin) if args.tspan is None: Tspan = model_utils.get_tspan([psr]) else: Tspan = args.tspan tm = gp_signals.TimingModel() log10_rho = parameter.Uniform(-10, -4, size=30) fs = gp_priors.free_spectrum(log10_rho=log10_rho) wn = blocks.white_noise_block(inc_ecorr=True) log10_A = parameter.Constant() gamma = parameter.Constant() plaw_pr = gp_priors.powerlaw(log10_A=log10_A, gamma=gamma) plaw = gp_signals.FourierBasisGP(plaw_pr, components=30, Tspan=Tspan) rn = gp_signals.FourierBasisGP(fs, components=30, Tspan=Tspan, name='excess_noise') m = tm + wn + plaw + rn if args.gwb_on: gw_log10_A = parameter.Constant('gw_log10_A') gw_gamma = parameter.Constant(4.3333)('gw_gamma')