def Cred_100ns(alphaab,times_f,A=5.77e-22,alpha=1.7,fL=1.0/10000): corr = N.zeros((len(times_f),len(times_f)),'d') ps, ts = len(alphaab), len(times_f) / len(alphaab) if not isinstance(A,(list,tuple,N.ndarray)): A = [A] * ps if not isinstance(alpha,(list,tuple,N.ndarray)): alpha = [alpha] * ps for i in range(ps): t1, t2 = N.meshgrid(times_f[i*ts:(i+1)*ts],times_f[i*ts:(i+1)*ts]) # t1, t2 are in days x = 2 * math.pi * (day/year) * fL * N.abs(t1 - t2) if abs(alpha[i] - 2.0) < 1e-7: power = (-math.pi/2 + (math.pi/2 - math.pi*EulerGamma/2) * (alpha[i] - 2.0)) * x**(alpha[i] - 1) else: power = SS.gamma(1-alpha[i]) * math.sin(0.5*math.pi*alpha[i]) * x**(alpha[i] - 1) # HypergeometricPFQ[{1/2-alpha/2},{1/2,3/2-alpha/2},-(1/4)fL^2 Tau^2]/(alpha - 1) ksum = SS.hyp1f2(0.5 - 0.5*alpha[i],0.5,1.5-0.5*alpha[i],-0.25*x**2)[0] / (alpha[i] - 1) # this must be multiplied with an amplitude given in units of s^(3-alpha), # so it must have units of s^(alpha - 1) to yield s^2; # we further multiply by 1e14 for units of 100 ns corr[i*ts:(i+1)*ts,i*ts:(i+1)*ts] = (A[i] * 1.0e14 * year**(alpha[i] - 1) * fL**(1-alpha[i])) * (power + ksum) return corr
def PL_covfunc(tau, amp, alpha=-2.0 / 3.0, fL=1.0 / (year * 20)): """ Compute the covariance function for a powerlaw Result is in units of (sec)^2. :param tau: the time lag :param amp: amplitude :param alpha: the GWB spectral index :param fL: the low-frequency cut-off """ fL = fL * year x = 2 * np.pi * fL * np.abs(tau) / year cf = ss.gamma(-2 + 2 * alpha) * np.cos(np.pi * alpha) power = cf * x ** (2 - 2 * alpha) ksum = ss.hyp1f2(alpha - 1, 0.5, alpha, -0.25 * x ** 2)[0] / (2 * alpha - 2) corr = -(year ** 2 * fL ** (-2 + 2 * alpha)) / (12 * np.pi ** 2) * (power + ksum) return amp ** 2 * corr
def PL_covfunc(tau, amp, alpha=-2.0/3.0, fL=1.0/(year*20)): """ Compute the covariance function for a powerlaw Result is in units of (sec)^2. :param tau: the time lag :param amp: amplitude :param alpha: the GWB spectral index :param fL: the low-frequency cut-off """ fL = fL * year x = 2 * np.pi * fL * np.abs(tau) / year cf = ss.gamma(-2+2*alpha) * np.cos(np.pi*alpha) power = cf * x**(2-2*alpha) ksum = ss.hyp1f2(alpha-1,0.5,alpha,-0.25*x**2)[0]/(2*alpha-2) corr = -(year**2 * fL**(-2+2*alpha)) / (12 * np.pi**2) * (power + ksum) return amp**2*corr
def S_alpha_wing(z, Tk): alf = eta_lya(Tk) * (3. * a_voigt(Tk) / 2. / np.pi / gammaGP(z))**(1. / 3.) OneMinusSalpha = 4. * alf / 9. * ( 3.**(2. / 3.) * np.pi * special.airy(-2. * alf / 3.**(1. / 3.))[2] + (3. * alf**2.) * special.hyp1f2(1., 4. / 3., 5. / 3., -8. * alf**3. / 27.)[0]) return 1. - OneMinusSalpha
def Cgw_days(alphaab,times_f,alpha=-2/3,fL=1.0/10000,approx_ksum=False): """Compute the residual covariance matrix for an hc = 1 x (f year)^alpha GW background. Result is in units of (days)^2.""" t1, t2 = N.meshgrid(times_f,times_f) # t1, t2 are in units of days x = 2 * math.pi * N.abs(t1 - t2) power = (day/year)**(-2*alpha) * (SS.gamma(-2+2*alpha) * math.cos(math.pi*alpha)) * x**(2-2*alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), {n, 0, Infinity}] # as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, -(x^2/4)]/(2 alpha - 2) # the corresponding scipy.special function is hyp1f2 (which returns value and error) # TO DO, for speed: could replace with the first few terms of the sum! # ksum = SS.hyp1f2(alpha-1,0.5,alpha,-0.25*x**2)[0]/(2*alpha-2) if not fL: # do not include any low-fcut correction ksum = 0 else: fLd = (day/year) * fL if approx_ksum: ksum = (year/day)**2 * fL**(-2+2*alpha) * (1.0 / (2*alpha - 2) - (fLd * x)**2 / (4*alpha) + (fLd * x)**4 / (24 * (2 + 2*alpha))) else: ksum = (year/day)**2 * fL**(-2+2*alpha) * SS.hyp1f2(alpha-1,0.5,alpha,-0.25*(fLd * x)**2)[0]/(2*alpha-2) corr = -(power + ksum) / (12 * math.pi**2) # multiply by alphaab; there must be a more numpythonic way to do it ps, ts = len(alphaab), len(times_f) / len(alphaab) for i in range(ps): for j in range(ps): corr[i*ts:(i+1)*ts,j*ts:(j+1)*ts] *= alphaab[i,j] return corr
def _mom(self, k): output = numpy.array([ special.hyp1f2(k_ + .5, .5, k_ + 1.5, -numpy.pi**2 / 4)[0] for k_ in k.flatten() ]).reshape(k.shape) output = 1 / (1. + k) + 1 / (1. + 2 * k) * output output = numpy.where(k % 2, output, 0) return output
def hyp1f2(a, b, c, x): v, err = sc.hyp1f2(a, b, c, x) if abs(err) > max(1, abs(v)) * 1e-7: return np.nan return v
def _mom(self, k): return np.where(k%2, 0, 2/(k+2) + 1/(k+1)*\ special.hyp1f2((k+1)/2.), .5, (k+3)/2., -np.pi**2/4)
def pl_cov(t, Si=4.33, fL=1.0/20, approx_ksum=False): """ Analytically calculate the covariance matrix for a stochastic signal with a power spectral density given by pl_psd. @param t: Time-series timestamps @param Si: Spectral index of power-law spectrum @param fL: Low-frequency cut-off @param approx_ksum: Whether we approximate the infinite sum @return: Covariance matrix """ EulerGamma = 0.5772156649015329 alpha = 0.5*(3.0-Si) # Make a mesh-grid for the covariance matrix elements t1, t2 = np.meshgrid(t,t) x = 2 * np.pi * fL * np.abs(t1 - t2) del t1 del t2 # The tolerance for which to use the Gamma function expansion tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small # interval around them... if abs(alpha) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = cosx - x * sinx sinint, cosint = sl.sici(x) corr = (fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = ss.sici(x) corr = (fL**-4) / (288 * np.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 # and 0.5 if abs(alpha - 0.5) < tol: cf = np.pi/2 + (np.pi - np.pi*EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -np.pi/12 + (-11*np.pi/36 + EulerGamma*math.pi/6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = np.pi/240 + (137*np.pi/7200 - EulerGamma*np.pi/120) * (alpha + 1.5) else: cf = ss.gamma(-2+2*alpha) * np.cos(np.pi*alpha) power = cf * x**(2-2*alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), # {n, 0, Infinity}] as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, # -(x^2/4)]/(2 alpha - 2) the corresponding scipy.special function is # hyp1f2 (which returns value and error) if approx_ksum: ksum = 1.0 / (2*alpha - 2) - x**2 / (4*alpha) + x**4 / (24 * (2 + 2*alpha)) else: ksum = ss.hyp1f2(alpha-1,0.5,alpha,-0.25*x**2)[0]/(2*alpha-2) del x corr = -(fL**(-2+2*alpha)) * (power + ksum) return corr
def Cgw_sec(model, alpha=-2.0/3.0, fL=1.0/500, approx_ksum=False, inc_cor=True): """ Compute the residual covariance matrix for an hc = 1 x (f year)^alpha GW background. Result is in units of (100 ns)^2. Modified from Michele Vallisneri's mc3pta (https://github.com/vallis/mc3pta) @param: list of libstempo pulsar objects (as returned by readRealisations) @param: the H&D correlation matrix @param: the TOAs @param: the GWB spectral index @param: the low-frequency cut-off @param: approx_ksum """ psrobs = model[6] alphaab = model[5] times_f = model[0] day = 86400.0 # seconds, sidereal (?) year = 3.15581498e7 # seconds, sidereal (?) EulerGamma = 0.5772156649015329 npsrs = alphaab.shape[0] t1, t2 = np.meshgrid(times_f,times_f) # t1, t2 are in units of days; fL in units of 1/year (sidereal for both?) # so typical values here are 10^-6 to 10^-3 x = 2 * np.pi * (day/year) * fL * np.abs(t1 - t2) del t1 del t2 # note that the gamma is singular for all half-integer alpha < 1.5 # # for -1 < alpha < 0, the x exponent ranges from 4 to 2 (it's 3.33 for alpha = -2/3) # so for the lower alpha values it will be comparable in value to the x**2 term of ksum # # possible alpha limits for a search could be [-0.95,-0.55] in which case the sign of `power` # is always positive, and the x exponent ranges from ~ 3 to 4... no problem with cancellation # The tolerance for which to use the Gamma function expansion tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small interval around them... if abs(alpha) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = cosx - x * sinx sinint, cosint = sl.sici(x) corr = (year**2 * fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = ss.sici(x) corr = (year**2 * fL**-4) / (288 * np.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 and 0.5 if abs(alpha - 0.5) < tol: cf = np.pi/2 + (np.pi - np.pi*EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -np.pi/12 + (-11*np.pi/36 + EulerGamma*math.pi/6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = np.pi/240 + (137*np.pi/7200 - EulerGamma*np.pi/120) * (alpha + 1.5) else: cf = ss.gamma(-2+2*alpha) * np.cos(np.pi*alpha) power = cf * x**(2-2*alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), {n, 0, Infinity}] # as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, -(x^2/4)]/(2 alpha - 2) # the corresponding scipy.special function is hyp1f2 (which returns value and error) # TO DO, for speed: could replace with the first few terms of the sum! if approx_ksum: ksum = 1.0 / (2*alpha - 2) - x**2 / (4*alpha) + x**4 / (24 * (2 + 2*alpha)) else: ksum = ss.hyp1f2(alpha-1,0.5,alpha,-0.25*x**2)[0]/(2*alpha-2) del x # this form follows from Eq. (A31) of Lee, Jenet, and Price ApJ 684:1304 (2008) corr = -(year**2 * fL**(-2+2*alpha)) / (12 * np.pi**2) * (power + ksum) if inc_cor: # multiply by alphaab; there must be a more numpythonic way to do it # npsrs psrobs inda, indb = 0, 0 for a in range(npsrs): for b in range(npsrs): corr[inda:inda+psrobs[a], indb:indb+psrobs[b]] *= alphaab[a, b] indb += psrobs[b] indb = 0 inda += psrobs[a] return corr
def Cred_sec(toas, alpha=-2.0/3.0, fL=1.0/20, approx_ksum=False): day = 86400.0 year = 3.15581498e7 EulerGamma = 0.5772156649015329 psrobs = [len(toas)] alphaab = np.array([[1.0]]) times_f = toas / day npsrs = alphaab.shape[0] t1, t2 = np.meshgrid(times_f,times_f) # t1, t2 are in units of days; fL in units of 1/year (sidereal for both?) # so typical values here are 10^-6 to 10^-3 x = 2 * np.pi * (day/year) * fL * np.abs(t1 - t2) del t1 del t2 # note that the gamma is singular for all half-integer alpha < 1.5 # # for -1 < alpha < 0, the x exponent ranges from 4 to 2 (it's 3.33 for alpha = -2/3) # so for the lower alpha values it will be comparable in value to the x**2 term of ksum # # possible alpha limits for a search could be [-0.95,-0.55] in which case the sign of `power` # is always positive, and the x exponent ranges from ~ 3 to 4... no problem with cancellation # The tolerance for which to use the Gamma function expansion tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small interval around them... if abs(alpha) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = cosx - x * sinx sinint, cosint = sl.sici(x) corr = (year**2 * fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = ss.sici(x) corr = (year**2 * fL**-4) / (288 * np.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 and 0.5 if abs(alpha - 0.5) < tol: cf = np.pi/2 + (np.pi - np.pi*EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -np.pi/12 + (-11*np.pi/36 + EulerGamma*math.pi/6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = np.pi/240 + (137*np.pi/7200 - EulerGamma*np.pi/120) * (alpha + 1.5) else: cf = ss.gamma(-2+2*alpha) * np.cos(np.pi*alpha) power = cf * x**(2-2*alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), {n, 0, Infinity}] # as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, -(x^2/4)]/(2 alpha - 2) # the corresponding scipy.special function is hyp1f2 (which returns value and error) # TO DO, for speed: could replace with the first few terms of the sum! if approx_ksum: ksum = 1.0 / (2*alpha - 2) - x**2 / (4*alpha) + x**4 / (24 * (2 + 2*alpha)) else: ksum = ss.hyp1f2(alpha-1,0.5,alpha,-0.25*x**2)[0]/(2*alpha-2) del x # this form follows from Eq. (A31) of Lee, Jenet, and Price ApJ 684:1304 (2008) corr = -(year**2 * fL**(-2+2*alpha)) / (12 * np.pi**2) * (power + ksum) return corr
def Cgw_sec(model, alpha=-2.0 / 3.0, fL=1.0 / 500, approx_ksum=False, inc_cor=True): """ Compute the residual covariance matrix for an hc = 1 x (f year)^alpha GW background. Result is in units of (100 ns)^2. Modified from Michele Vallisneri's mc3pta (https://github.com/vallis/mc3pta) @param: list of libstempo pulsar objects (as returned by readRealisations) @param: the H&D correlation matrix @param: the TOAs @param: the GWB spectral index @param: the low-frequency cut-off @param: approx_ksum """ psrobs = model[6] alphaab = model[5] times_f = model[0] day = 86400.0 # seconds, sidereal (?) year = 3.15581498e7 # seconds, sidereal (?) EulerGamma = 0.5772156649015329 npsrs = alphaab.shape[0] t1, t2 = np.meshgrid(times_f, times_f) # t1, t2 are in units of days; fL in units of 1/year (sidereal for both?) # so typical values here are 10^-6 to 10^-3 x = 2 * np.pi * (day / year) * fL * np.abs(t1 - t2) del t1 del t2 # note that the gamma is singular for all half-integer alpha < 1.5 # # for -1 < alpha < 0, the x exponent ranges from 4 to 2 (it's 3.33 for alpha = -2/3) # so for the lower alpha values it will be comparable in value to the x**2 term of ksum # # possible alpha limits for a search could be [-0.95,-0.55] in which case the sign of `power` # is always positive, and the x exponent ranges from ~ 3 to 4... no problem with cancellation # The tolerance for which to use the Gamma function expansion tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small interval around them... if abs(alpha) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = cosx - x * sinx sinint, cosint = sl.sici(x) corr = (year**2 * fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = ss.sici(x) corr = (year**2 * fL**-4) / (288 * np.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 and 0.5 if abs(alpha - 0.5) < tol: cf = np.pi / 2 + (np.pi - np.pi * EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -np.pi / 12 + (-11 * np.pi / 36 + EulerGamma * math.pi / 6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = np.pi / 240 + (137 * np.pi / 7200 - EulerGamma * np.pi / 120) * (alpha + 1.5) else: cf = ss.gamma(-2 + 2 * alpha) * np.cos(np.pi * alpha) power = cf * x**(2 - 2 * alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), {n, 0, Infinity}] # as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, -(x^2/4)]/(2 alpha - 2) # the corresponding scipy.special function is hyp1f2 (which returns value and error) # TO DO, for speed: could replace with the first few terms of the sum! if approx_ksum: ksum = 1.0 / (2 * alpha - 2) - x**2 / (4 * alpha) + x**4 / (24 * (2 + 2 * alpha)) else: ksum = ss.hyp1f2(alpha - 1, 0.5, alpha, -0.25 * x**2)[0] / (2 * alpha - 2) del x # this form follows from Eq. (A31) of Lee, Jenet, and Price ApJ 684:1304 (2008) corr = -(year**2 * fL**(-2 + 2 * alpha)) / (12 * np.pi**2) * (power + ksum) if inc_cor: # multiply by alphaab; there must be a more numpythonic way to do it # npsrs psrobs inda, indb = 0, 0 for a in range(npsrs): for b in range(npsrs): corr[inda:inda + psrobs[a], indb:indb + psrobs[b]] *= alphaab[a, b] indb += psrobs[b] indb = 0 inda += psrobs[a] return corr
def approxBesselInt(b, q, r): return 0.5 * q**(-2.0 - b) * spec.gamma(-b / 2.0 - 1.0) * spec.hyp1f2( -b / 2.0 - 1.0, 1, -b / 2.0, q**2 * r**2 / 4.0)[0] / (spec.gamma(1) * spec.gamma(-b / 2.0))
def _cosine_volume(dim): hyp, _ = hyp1f2(0.5 * dim, 0.5, 0.5 * dim + 1, -_PI_SQ / 16.0) return _vn(dim) * (_PI_2 ** dim) * hyp
def _mom(self, k): output = numpy.array([special.hyp1f2(k_+.5, .5, k_+1.5, -numpy.pi**2/4)[0] for k_ in k.flatten()]).reshape(k.shape) output = 1/(1.+k) + 1/(1.+2*k)*output output = numpy.where(k % 2, output, 0) return output
def Cgw_sec(toas, alpha=-2.0 / 3.0, fL=1.0 / 20, approx_ksum=False): day = 86400.0 year = 3.15581498e7 EulerGamma = 0.5772156649015329 psrobs = [len(toas)] alphaab = np.array([[1.0]]) times_f = toas / day npsrs = alphaab.shape[0] t1, t2 = np.meshgrid(times_f, times_f) # t1, t2 are in units of days; fL in units of 1/year (sidereal for both?) # so typical values here are 10^-6 to 10^-3 x = 2 * np.pi * (day / year) * fL * np.abs(t1 - t2) del t1 del t2 # note that the gamma is singular for all half-integer alpha < 1.5 # # for -1 < alpha < 0, the x exponent ranges from 4 to 2 (it's 3.33 for alpha = -2/3) # so for the lower alpha values it will be comparable in value to the x**2 term of ksum # # possible alpha limits for a search could be [-0.95,-0.55] in which case the sign of `power` # is always positive, and the x exponent ranges from ~ 3 to 4... no problem with cancellation # The tolerance for which to use the Gamma function expansion tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small interval around them... if abs(alpha) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = cosx - x * sinx sinint, cosint = sl.sici(x) corr = (year**2 * fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = ss.sici(x) corr = (year**2 * fL**-4) / (288 * np.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 and 0.5 if abs(alpha - 0.5) < tol: cf = np.pi / 2 + (np.pi - np.pi * EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -np.pi / 12 + (-11 * np.pi / 36 + EulerGamma * math.pi / 6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = np.pi / 240 + (137 * np.pi / 7200 - EulerGamma * np.pi / 120) * (alpha + 1.5) else: cf = ss.gamma(-2 + 2 * alpha) * np.cos(np.pi * alpha) power = cf * x**(2 - 2 * alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), {n, 0, Infinity}] # as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, -(x^2/4)]/(2 alpha - 2) # the corresponding scipy.special function is hyp1f2 (which returns value and error) # TO DO, for speed: could replace with the first few terms of the sum! if approx_ksum: ksum = 1.0 / (2 * alpha - 2) - x**2 / (4 * alpha) + x**4 / (24 * (2 + 2 * alpha)) else: ksum = ss.hyp1f2(alpha - 1, 0.5, alpha, -0.25 * x**2)[0] / (2 * alpha - 2) del x # this form follows from Eq. (A31) of Lee, Jenet, and Price ApJ 684:1304 (2008) corr = -(year**2 * fL**(-2 + 2 * alpha)) / (12 * np.pi**2) * (power + ksum) return corr
def Cgw_100ns(alphaab,times_f,alpha=-2/3,fL=1.0/10000,approx_ksum=False): """Compute the residual covariance matrix for an hc = 1 x (f year)^alpha GW background. Result is in units of (100 ns)^2.""" t1, t2 = N.meshgrid(times_f,times_f) # t1, t2 are in units of days; fL in units of 1/year (sidereal for both?) # so typical values here are 10^-6 to 10^-3 x = 2 * math.pi * (day/year) * fL * N.abs(t1 - t2) # note that the gamma is singular for all half-integer alpha < 1.5 # # for -1 < alpha < 0, the x exponent ranges from 4 to 2 (it's 3.33 for alpha = -2/3) # so for the lower alpha values it will be comparable in value to the x**2 term of ksum # # possible alpha limits for a search could be [-0.95,-0.55] in which case the sign of `power` # is always positive, and the x exponent ranges from ~ 3 to 4... no problem with cancellation # the variance, as computed below, is in units of year^2; we convert it # to units of (100 ns)^2, so the multiplier is ~ 10^28 year100ns = year/1e-7 tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small interval around them... if abs(alpha) < 1e-7: cosx, sinx = N.cos(x), N.sin(x) power = cosx - x * sinx sinint, cosint = SL.sici(x) corr = (year100ns**2 * fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = N.cos(x), N.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = SL.sici(x) corr = (year100ns**2 * fL**-4) / (288 * math.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 and 0.5 if abs(alpha - 0.5) < tol: cf = math.pi/2 + (math.pi - math.pi*EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -math.pi/12 + (-11*math.pi/36 + EulerGamma*math.pi/6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = math.pi/240 + (137*math.pi/7200 - EulerGamma*math.pi/120) * (alpha + 1.5) else: cf = SS.gamma(-2+2*alpha) * math.cos(math.pi*alpha) power = cf * x**(2-2*alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), {n, 0, Infinity}] # as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, -(x^2/4)]/(2 alpha - 2) # the corresponding scipy.special function is hyp1f2 (which returns value and error) # TO DO, for speed: could replace with the first few terms of the sum! if approx_ksum: ksum = 1.0 / (2*alpha - 2) - x**2 / (4*alpha) + x**4 / (24 * (2 + 2*alpha)) else: ksum = SS.hyp1f2(alpha-1,0.5,alpha,-0.25*x**2)[0]/(2*alpha-2) # this form follows from Eq. (A31) of Lee, Jenet, and Price ApJ 684:1304 (2008) corr = -(year100ns**2 * fL**(-2+2*alpha)) / (12 * math.pi**2) * (power + ksum) # multiply by alphaab; there must be a more numpythonic way to do it ps, ts = len(alphaab), len(times_f) / len(alphaab) for i in range(ps): for j in range(ps): corr[i*ts:(i+1)*ts,j*ts:(j+1)*ts] *= alphaab[i,j] return corr
def pl_cov(t, Si=4.33, fL=1.0 / 20, approx_ksum=False): """ Analytically calculate the covariance matrix for a stochastic signal with a power spectral density given by pl_psd. @param t: Time-series timestamps @param Si: Spectral index of power-law spectrum @param fL: Low-frequency cut-off @param approx_ksum: Whether we approximate the infinite sum @return: Covariance matrix """ EulerGamma = 0.5772156649015329 alpha = 0.5 * (3.0 - Si) # Make a mesh-grid for the covariance matrix elements t1, t2 = np.meshgrid(t, t) x = 2 * np.pi * fL * np.abs(t1 - t2) del t1 del t2 # The tolerance for which to use the Gamma function expansion tol = 1e-5 # the exact solutions for alpha = 0, -1 should be acceptable in a small # interval around them... if abs(alpha) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = cosx - x * sinx sinint, cosint = sl.sici(x) corr = (fL**-2) / (24 * math.pi**2) * (power + x**2 * cosint) elif abs(alpha + 1) < 1e-7: cosx, sinx = np.cos(x), np.sin(x) power = 6 * cosx - 2 * x * sinx - x**2 * cosx + x**3 * sinx sinint, cosint = ss.sici(x) corr = (fL**-4) / (288 * np.pi**2) * (power - x**4 * cosint) else: # leading-order expansion of Gamma[-2+2*alpha]*Cos[Pi*alpha] around -0.5 # and 0.5 if abs(alpha - 0.5) < tol: cf = np.pi / 2 + (np.pi - np.pi * EulerGamma) * (alpha - 0.5) elif abs(alpha + 0.5) < tol: cf = -np.pi / 12 + (-11 * np.pi / 36 + EulerGamma * math.pi / 6) * (alpha + 0.5) elif abs(alpha + 1.5) < tol: cf = np.pi / 240 + (137 * np.pi / 7200 - EulerGamma * np.pi / 120) * (alpha + 1.5) else: cf = ss.gamma(-2 + 2 * alpha) * np.cos(np.pi * alpha) power = cf * x**(2 - 2 * alpha) # Mathematica solves Sum[(-1)^n x^(2 n)/((2 n)! (2 n + 2 alpha - 2)), # {n, 0, Infinity}] as HypergeometricPFQ[{-1+alpha}, {1/2,alpha}, # -(x^2/4)]/(2 alpha - 2) the corresponding scipy.special function is # hyp1f2 (which returns value and error) if approx_ksum: ksum = 1.0 / (2 * alpha - 2) - x**2 / (4 * alpha) + x**4 / (24 * (2 + 2 * alpha)) else: ksum = ss.hyp1f2(alpha - 1, 0.5, alpha, -0.25 * x**2)[0] / (2 * alpha - 2) del x corr = -(fL**(-2 + 2 * alpha)) * (power + ksum) return corr
def _cosine_volume(dim): hyp, _ = hyp1f2(0.5 * dim, 0.5, 0.5 * dim + 1, -_PI_SQ / 16.0) return _vn(dim) * (_PI_2**dim) * hyp