def _fourier_analytic(self, cosmo, k, M, a, mass_def): M_use = np.atleast_1d(M) k_use = np.atleast_1d(k) # Comoving virial radius R_M = mass_def.get_radius(cosmo, M_use, a) / a c_M = self._get_cM(cosmo, M_use, a, mdef=mass_def) R_s = R_M / c_M x = k_use[None, :] * R_s[:, None] Si2, Ci2 = sici(x) P1 = M / (np.log(1 + c_M) - c_M / (1 + c_M)) if self.truncated: Si1, Ci1 = sici((1 + c_M[:, None]) * x) P2 = np.sin(x) * (Si1 - Si2) + np.cos(x) * (Ci1 - Ci2) P3 = np.sin(c_M[:, None] * x) / ((1 + c_M[:, None]) * x) prof = P1[:, None] * (P2 - P3) else: P2 = np.sin(x) * (0.5 * np.pi - Si2) - np.cos(x) * Ci2 prof = P1[:, None] * P2 if np.ndim(k) == 0: prof = np.squeeze(prof, axis=-1) if np.ndim(M) == 0: prof = np.squeeze(prof, axis=0) return prof
def B_FT_integral(self, k): rst = 0.015 * self.r200 rs = self.r_scale si_1, ci_1 = sici(k * rst) si_2, ci_2 = sici(k * (rst + self.r200)) si_3, ci_3 = sici(k * rs) si_4, ci_4 = sici(k * (rs + self.r200)) prefac = rs**3. * rst**2. / (rs - rst)**3. term1 = k * (-rs + rst) * np.cos(k * rst) * ci_1 term2 = k * (rs - rst) * np.cos(k * rst) * ci_2 term3 = -(rs - rst) * (2 * self.r200 + rs + rst) * np.sin( k * self.r200) / (self.r200 + rs) / (self.r200 + rst) term4 = ci_4 * (k * (rs - rst) * np.cos(k * rs) - 2 * np.sin(k * rs)) term5 = ci_3 * (k * (rst - rs) * np.cos(k * rs) + 2 * np.sin(k * rs)) term6 = -2. * ci_1 * np.sin(k * rst) + 2. * ci_2 * np.sin(k * rst) term7 = -k * (rs - rst) * np.sin(k * rs) * si_3 term8 = k * (rs - rst) * np.sin(k * rs) * si_4 term9 = 2. * np.cos(k * rs) * (-si_3 + si_4) + 2. * np.cos( k * rst) * si_1 - k * (rs - rst) * np.sin(k * rst) * si_1 term10 = -2 * np.cos(k * rst) * si_2 + k * (rs - rst) * np.sin( k * rst) * si_2 return prefac * (term1 + term2 + term3 + term4 + term5 + term6 + term7 + term8 + term9 + term10)
def fourier_profiles(self, cosmo, k, M, a, squeeze=True, **kwargs): """ Computes the Fourier transform of the Navarro-Frenk-White profile. """ # Input handling M, a, k = np.atleast_1d(M), np.atleast_1d(a), np.atleast_2d(k) # extract parameters bg = kwargs.get("beta_gal", 1.) bmax = kwargs.get("beta_max", 1.) c = concentration_duffy(M, a, is_D500=True, squeeze=False) R = R_Delta(cosmo, M, a, self.Delta, is_matter=False, squeeze=False) / (c * a) x = k * R[..., None] c = c[..., None] * bmax # optimise Si1, Ci1 = sici((bg + c) * x) Si2, Ci2 = sici(bg * x) P1 = 1 / (np.log(1 + c / bg) - c / (1 + c / bg)) P2 = np.sin(bg * x) * (Si1 - Si2) + np.cos(bg * x) * (Ci1 - Ci2) P3 = np.sin(c * x) / ((bg + c) * x) F = P1 * (P2 - P3) return (F.squeeze(), (F**2).squeeze()) if squeeze else (F, F**2)
def utconvut(r, rt, conc): """1-halo contribution to be substracted from the 2-halo term (ximm). Args: r (float or array like): 3d distances from halo center in Mpc/h comoving. rt (float): Truncation radius. The boundary of the halo. conc (float): Concentration. Returns: float or arraylike: 1-halo contribution. """ # Get ut(k) # Analytic expression k = np.logspace(-4, 4, num=1000, base=10) rc = rt / conc mu = k * rc Put = (np.cos(mu) * (sici(mu + mu * conc)[1] - sici(mu)[1]) + np.sin(mu) * (sici(mu + mu * conc)[0] - sici(mu)[0]) - np.sin(mu * conc) / (mu + mu * conc)) \ / (np.log(1 + conc) - conc / (1 + conc)) # Product PutPut = Put * Put # Transform to real space integral = fastcorr.calc_corr(r, k, PutPut, N=500, h=1e-2) return integral
def impedance(self, wvln, Z): """ Impedance of a dipole antenna Reference:: https://en.wikipedia.org/wiki/Dipole_antenna#General_impedance_formulas @param wvln : wavelength (m) @type wvln : (numpy array of) float @param Z : impedance of the medium, 376.73 ohm for free space """ k = 2*math.pi*wavenumber(wvln) x = k*self.length try: from scipy.special import sici Si,Ci = sici(x) SiTwo,CiTwo = sici(2*x) Sia, Cia = sici(2*k*self.radius*self.radius/self.length) except ImportError: Si,Ci = sin(x), cos(x) SiTwo,CiTwo = sin(2*x), cos(2*x) a = 2*k*self.radius*self.radius/self.length Sia, Cia = sin(a), cos(a) multiplier = Z/(2*math.pi*numpy.sin(x/2.)**2) R = multiplier * (euler + numpy.log(x) - Ci +0.5*numpy.sin(x)*(SiTwo - 2*Si) +0.5*numpy.cos(x)*(euler + numpy.log(x/2.) + CiTwo -2*Ci)) X = (multiplier/2.) * (2*Si + numpy.cos(x)*(2*Si - SiTwo) - numpy.sin(x)*(2*Ci - CiTwo - Cia)) return R, X
def u_nfw(self, k, m, z): """ Normalized Fourier Transform of an NFW profile. ..note:: This is Equation 81 from Cooray & Sheth (2002). Parameters ---------- k : int, float Wavenumber m : """ c, r_s = self.cm_relation(m, z, get_rs=True) K = k * r_s asi, ac = sp.sici((1 + c) * K) bs, bc = sp.sici(K) # The extra factor of np.log(1 + c) - c / (1 + c)) comes in because # there's really a normalization factor of 4 pi rho_s r_s^3 / m, # and m = 4 pi rho_s r_s^3 * the log term norm = 1. / (np.log(1 + c) - c / (1 + c)) return norm * (np.sin(K) * (asi - bs) - np.sin(c * K) / ((1 + c) * K) \ + np.cos(K) * (ac - bc))
def psi_SFS_simple3d(d, prefac, xi, d0): """Return simple clean limit pair wavefunction from Demler """ a = (d - d0)/xi (si,ci) = sici(a) vc = abs(prefac*(-np.pi/2*(a) + a*sici(a)[0] + np.cos(a))) return vc
def NFW_k(self, k, m, normalize=True): ''' This parameterization is from Scoccimarro et al. 2000 "How Many Galaxies Fit in a Halo?" ''' R = self.mass_2_virial_radius(m).to( u.Mpc).value * self.Delta**(1. / 3.) c = self.concentration(m) khat = k * self.R_star * self.Delta**(-1. / 3.) y = ((R / self.R_star) / self.h) kappa = np.array( [khat.value * y[i].value / c[i].value for i in range(len(c))]) kappa_c = np.array([kappa[i] * c[i].value for i in range(len(c))]) kappa_1plus_c = np.array( [kappa[i] * (1. + c[i].value) for i in range(len(c))]) SI_1, CI_1 = sici(kappa_1plus_c) SI_2, CI_2 = sici(kappa) # no fs given, yet... ufunc_no_f = np.sin(kappa) * (SI_1 - SI_2) + np.cos(kappa) * ( CI_1 - CI_2) - (np.sin(kappa_c) / kappa_1plus_c) fs = self.f(c) ufunc = np.array([fs[i] * ufunc_no_f[i] for i in range(len(c))]) if normalize: return np.array( [ufunc[i] / np.max(ufunc[i]) for i in range(ufunc.shape[0])]) else: return ufunc
def fk(k): x = k * r_s Si1, Ci1 = sici((1 + c) * x) Si2, Ci2 = sici(x) P1 = 1 / (np.log(1 + c) - c / (1 + c)) P2 = np.sin(x) * (Si1 - Si2) + np.cos(x) * (Ci1 - Ci2) P3 = np.sin(c * x) / ((1 + c) * x) return M * P1 * (P2 - P3)
def antideriv(k, x): si1, ci1 = sici(k * (x + 1)) si2, ci2 = sici(k * (x + 0.75)) return (1. / k) * ( 12 * (np.cos(k) * si1 - np.sin(k) * ci1) + 4 * k * (np.cos(k) * ci1 + np.sin(k) * si1) - 4 * np.sin(k * x) / (x + 1) + -12 * (np.cos(0.75 * k) * si2 - np.sin(0.75 * k) * ci2))
def __init__(self, flip_d, Trf, side_lobes=1, B0=_defaultB0): flip_r = np.radians(flip_d) self.flip_d = flip_d self.flip_r = flip_r self.length = Trf self.N = 2 * (side_lobes + 1) # +1 for central lobe, *2 for symmetric Npi = self.N * np.pi self.amp = flip_r / (B0 * _gamma2pi * Trf * special.sici(Npi)[0] / Npi) self.int_omega2 = Trf * \ (B0 * _gamma2pi * self.amp)**2 * special.sici(2*Npi)[0] / Npi
def _p(self, K, c): sk, ck = sp.sici(K) skp, ckp = sp.sici(K + c * K) f1 = K * ck * np.sin(K) - K * np.cos(K) * sk - 1 f2 = -((1 + c) * K * np.cos(c * K) + np.sin(c * K)) / (1 + c)**2 f3 = K**2 * (ckp * np.sin(K) - np.cos(K) * skp) return (-K / 2 * f1 + 0.5 * (f2 + f3)) / K
def FT_density(self, k): prefactor = 4. * np.pi * self.rho_s * self.r_scale**3 si_1, ci_1 = sici(k * self.r_scale) si_2, ci_2 = sici(k * (self.r_scale + self.r200)) bb = k * self.r_scale Xm = self.r200 / self.r_scale term1 = np.cos(bb) * (-ci_1 + ci_2) term2 = np.sin(bb) * (-si_1 + si_2) term3 = np.sin(bb * Xm) / ((1. + Xm) * bb) return prefactor * (term1 + term2 + term3)
def _p(self, K, c): sk, ck = sp.sici(K) skp, ckp = sp.sici(K + c * K) f1 = K * ck * np.sin(K) - K * np.cos(K) * sk - 1 f2 = -((1 + c) * K * np.cos(c * K) + np.sin(c * K)) / (1 + c) ** 2 f3 = K ** 2 * (ckp * np.sin(K) - np.cos(K) * skp) return (-K / 2 * f1 + 0.5 * (f2 + f3)) / K
def u_nfw(lm,k) : x=k*rsMf(lm) #k*r_s c=cMf(lm) sic,cic=sici(x*(1+c)) six,cix=sici(x) fsin=np.sin(x)*(sic-six) fcos=np.cos(x)*(cic-cix) fsic=np.sin(c*x)/(x*(1+c)) fcon=np.log(1.+c)-c/(1+c) return (fsin+fcos-fsic)/fcon
def frl1(x): gamma = pi / 3. a2 = (11. / 3. - np.log(2) - np.euler_gamma - np.log(x)) * np.cos( 2. * x) + (9. + np.cos(2. * x)) * sici(2. * x)[1] a1 = 15. - 9. * np.log(2.) - 9. * np.euler_gamma - 9. * np.log(x) + ( 2. * x + np.sin(2. * x)) * sici(2. * x)[0] b1 = 8. * (np.sin(2. * x) - (1 + np.cos(x)**2.) * x - np.sin(2. * x) * x * x) / x**3. c1 = nquad(frl, [[0., pi], [0., 2. * pi]], args=(x, gamma)) z = (a2 + a1 + b1 - c1[0]) / 8. / x / x return z
def y_halo_parameter2(k, M, halo_stuff, g): eta = k * halo_stuff.r_characteristic_array[g] c_eta = k * r_halo_virial(M) SiCi_term = np.subtract(sici((eta + c_eta)), sici(eta)) Si_term = SiCi_term[0] Ci_term = SiCi_term[1] factor = 1 / (np.log(1 + halo_stuff.c_concentration_array[g]) - halo_stuff.c_concentration_array[g] / (1 + halo_stuff.c_concentration_array[g])) return (factor * (np.sin(eta) * Si_term + np.cos(eta) * Ci_term - np.sin(c_eta) / (eta + c_eta)))
def W(k, M, z, model='diemer19', A=None, B=None, C=None, log10Mpv=None): ''' W(k, M) is the normalized Fourier transform of the halo density profile. Eq. (9) k : float Fourier Mode in (Mpc/h)^-1 M : float Halo mass in Msun/h z : float Redshift model : Colossus concentration model str (default diemer19) A : float (Only required if model == 'generic') c-M relation amplitude parameter B : float (Only required if model == 'generic') c-M relation power-law parameter C: float (Only required if model == 'generic') C-M relation minimum value log10Mpv : float (Only required if model == 'generic') c-M relation log10-mass pivot value ''' if model == 'generic': try: conc = (A * (M / (10**log10Mpv))**B) + C except TypeError: raise RuntimeError( "A, B, C, Mpv have to be explictly set if model is generic!") else: conc = concentration.concentration(M, '200c', z, model=model) # Getting the comoving parameters assuming 200c R200c = (3 * M / (4 * np.pi * 200 * rhoc))**(1.0 / 3) rs = R200c / conc * (1 + z) rhos = conc**3 / 3 * 200 * rhoc / (np.log(conc + 1) - conc / (conc + 1)) / (1 + z)**3 # Analytical Integration aux1 = k[:, np.newaxis] * (1.0 + conc) * rs aux2 = k[:, np.newaxis] * rs aux3 = k[:, np.newaxis] * conc * rs si1, ci1 = sici(aux1) si2, ci2 = sici(aux2) return 4.0 * np.pi * rhos * rs**3 *\ ( np.sin( aux2 ) * (si1-si2) - np.sinc(aux3/np.pi) * (conc/(1.0+conc)) +\ np.cos( aux2 ) * (ci1-ci2) )
def single_slit_model_with_integration(x, A, z, d, wl, s, offset): return A * (2 * z * (-(z - z * np.cos( (d * (2 * np.pi / wl) * (s - (x - offset))) / z) + d * (2 * np.pi / wl) * (s - (x - offset)) * sici( (d * (2 * np.pi / wl) * (-s + (x - offset))) / z)[0]) / (2. * (s - (x - offset)) * z) + ((-1 + np.cos( (d * (2 * np.pi / wl) * (s + (x - offset))) / z)) / (s + (x - offset)) + (d * (2 * np.pi / wl) * sici( (d * (2 * np.pi / wl) * (s + (x - offset))) / z)[0]) / z) / 2.)) / ( (2 * np.pi / wl) * np.pi)
def compute_integral(self, sinc_loc, sinc_amp, Omega, start_time, end_time, b=0): integral = b * (end_time - start_time) for l in range(len(sinc_loc)): integral += (sinc_amp[l] * (sici(Omega * (end_time - sinc_loc[l]))[0] - sici(Omega * (start_time - sinc_loc[l]))[0]) / np.pi) return integral
def dipoleImpedance( frequency, length, diameter ): radius = diameter/2 k = 2*pi*frequency/299792458 resistance_m = (eta/(2*pi))*(euler + log(k*length) - sici(k*length)[1] + 0.5*sin(k*length)*(sici(2*k*length)[0] - 2*sici(k*length)[0]) + 0.5*cos(k*length)*(euler + log(k*length/2) + sici(2*k*length)[1] - 2*sici(k*length)[1])) resistance = resistance_m / (sin(k*length/2)*sin(k*length/2)) reactance_m = (eta/(4*pi))*(2*sici(k*length)[0] + cos(k*length)*(2*sici(k*length)[0] - sici(2*k*length)[0]) - sin(k*length)*(2*sici(k*length)[1] - sici(2*k*length)[1] - sici(2*k*radius*radius/length)[1])) reactance = reactance_m / (sin(k*length/2)*sin(k*length/2)) impedance = complex(resistance, reactance) return impedance
def _normalized_halo_profile(self, k_h, r_virial, c): """Compute the normalized halo profile function in Fourier space; :math:`u(k|m)` For details of the available profile parametrizations, see the class description. Note that the function returns unity for :math:`k \\leq 0`. Args: k_h (np.ndarray): Wavenumber in h/Mpc units. r_virial (np.ndarray): Virial radius in Mpc/h units. c (np.ndarray): Halo concentration parameter; :math:`c = r_\mathrm{virial}/r_\mathrm{scale}`. Returns: np.ndarray: Normalized halo profile :math:`u(k|m)` """ if self.profile_name == 'NFW': r_scale = r_virial / c # in Mpc/h units # Check if we have an array or a float input and compute accordingly if type(k_h) == np.ndarray: # filter out sections with k_h<=0 filt = np.where(k_h > 0) # compute the matrix of r_scale * k_h ks0 = np.matmul(k_h.reshape(-1, 1), r_scale.reshape(1, -1)) ks = ks0[filt, :] else: if k_h <= 0.: return 1. ks = k_h * r_scale sici1 = sici(ks) sici2 = sici(ks * (1. + c)) f1 = np.sin(ks) * (sici2[0] - sici1[0]) f2 = np.cos(ks) * (sici2[1] - sici1[1]) f3 = np.sin(c * ks) / (ks * (1. + c)) fc = np.log(1. + c) - c / (1. + c) if type(k_h) == np.ndarray: output = np.ones_like(ks0) output[filt, :] = ((f1 + f2 - f3) / fc) return output else: return (f1 + f2 - f3) / fc else: raise NameError('Halo profile %s is not implemented yet' % (self.profile_name))
def func(f, amp, time, a, b, c): return -amp * ( ((f - a) / (b - a)) * (special.sici(time * 2 * math.pi * (f - a))[0] - special.sici(time * 2 * math.pi * (f - b))[0]) + (np.cos(time * 2 * math.pi * (f - a)) - np.cos(time * 2 * math.pi * (f - b))) / (time * 2 * math.pi * (b - a)) + ((c - f) / (b - c)) * (special.sici(time * 2 * math.pi * (f - c))[0] - special.sici(time * 2 * math.pi * (f - b))[0]) - (np.cos(time * 2 * math.pi * (f - c)) - np.cos(time * 2 * math.pi * (f - b))) / (time * 2 * math.pi * (b - c)))
def xysincs(uvecs: [np.ndarray], a: float, xi: float = 0.0): """ Solution for the xysincs model. Defined as: I(x,y) = sinc(ax) sinc(ay) cos(1 - x^2 - y^2), for |x| and |y| < 1/sqrt(2) = 0, otherwise where (x,y) is rotated from (l,m) by an angle xi. In UV space, this resembles a rotated square. Parameters ---------- uvecs: ndarray of float Cartesian baseline vectors in wavelengths, shape (Nbls, 3) a: float Sinc parameter, giving width of the "box" in uv space. box width in UV is a/(2 pi) xi: float Rotation of (x,y) coordinates from (l,m) in radians. Returns ------- ndarray of complex Visibilities, shape (Nbls,) """ assert uvecs.ndim == 2 and uvecs.shape[1] == 3 assert np.allclose(uvecs[:, 2], 0) cx, sx = np.cos(xi), np.sin(xi) rot = np.array([[cx, sx, 0], [-sx, cx, 0], [0, 0, 1]]) xyvecs = np.dot(uvecs, rot) x = 2 * np.pi * xyvecs[:, 0] y = 2 * np.pi * xyvecs[:, 1] x = x.astype(complex) y = y.astype(complex) b = 1 / np.sqrt(2.0) xfac = (np.sign(a - x) - np.sign(a - x)) * np.pi / 2 yfac = (np.sign(a - y) - np.sign(a - y)) * np.pi / 2 xpart = (sici(b * (a - x))[0] + sici(b * (a + x))[0] + xfac) / a ypart = (sici(b * (a - y))[0] + sici(b * (a + y))[0] + yfac) / a return ypart * xpart
def gen(x, name): """Generate fixture data and writes them to file. # Arguments * `x`: domain * `name::str`: output filename # Examples ``` python python> x = linspace(0.0, 1.0, 2001) python> gen(x, './data.json') ``` """ y = sici(x) # Store data to be written to file as a dictionary: data = {"x": x.tolist(), "si": y[0].tolist(), "ci": y[1].tolist()} # Based on the script directory, create an output filepath: filepath = os.path.join(DIR, name) # Write the data to the output filepath as JSON: with open(filepath, "w") as outfile: json.dump(data, outfile)
def test_sici_float32(self): x = np.array([[1, 2], [3, 4]], np.float32) x_gpu = gpuarray.to_gpu(x) (si_gpu, ci_gpu) = special.sici(x_gpu) (si, ci) = scipy.special.sici(x) np.testing.assert_allclose(si, si_gpu.get(), atol=1e-7) np.testing.assert_allclose(ci, ci_gpu.get(), atol=1e-7)
def __init__(self, pm): """Initializes variables parameters ---------- pm: object input parameters """ self.x_npt = pm.sys.grid self.x_delta = pm.sys.deltax # eqn (82) self.A = pm.lda.mix #kerker_length: float # screening distance for Kerker preconditioning [a0] # Default corresponds to :math:`2\pi/\lambda = 1.5\AA` self.q0 = 2 * np.pi / pm.lda.kerker_length dq = 2 * np.pi / (2 * pm.sys.xmax) q0_scaled = self.q0 / dq self.G_q = np.zeros((self.x_npt // 2 + 1), dtype=np.float) for q in range(len(self.G_q)): self.G_q[q] = self.A * q**2 / (q**2 + q0_scaled**2) #self.G_r = np.set_diagonal(diagonal # one-dimensional Kerker mixing a = pm.sys.acon q = dq * np.array(list(range(self.x_npt // 2 + 1))) aq = np.abs(a * q) Si, Ci = scsp.sici(aq) # verified that this agrees with Mathematica... v_k = -2 * (np.cos(aq) * Ci + np.sin(aq) * (Si - np.pi / 2)) self.G_q_1d = self.A * 1 / (1 + v_k * self.q0)
def test_sici_float64(self): x = np.array([[1, 2], [3, 4]], np.float64) x_gpu = gpuarray.to_gpu(x) (si_gpu, ci_gpu) = special.sici(x_gpu) (si, ci) = scipy.special.sici(x) assert np.allclose(si, si_gpu.get()) assert np.allclose(ci, ci_gpu.get())
def step_t_finite_overshoot(w1, w2, t0, width, t): """ Step function that goes from w1 to w2 at time t0 as a function of t, with finite rise time and and overshoot defined by the parameter width. """ return w1 + (w2 - w1) * (0.5 + sici((t - t0) / width)[0] / (np.pi))
def func2(): """Test fucntion sin(x)/x Returns: -f (function) The fucntion to be integrated -name (string) Function form in string -inte (fucntion) Analytic solution of the integral""" f = lambda x: np.sin(x)/x inte = lambda x: sici(x)[0] return f , "sin(x)/x", inte
def vc_SFS_B82_nearTc(d, prefac, xi_f, doff): """clean limit vc-d by Buzdin (1982) Transparent interface. """ a = (d - doff)/xi_f (si,ci) = sici(a) vc = prefac * abs( -1/2*(a**2*ci - a*np.sin(a) + np.cos(a)) ) return vc
def exact(x: float) -> float: def f1(r: float) -> Any: return (np.sin(r) / r) ** 2 # re-arranging the formula for sici from # https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.sici.html # to match Mehta (2004) p595, A.38, we get: int_2 = y + np.log(2 * p * x) - sici(2 * p * x)[1] # sici(x) returns (Sine integral from 0 to x, gamma + log(x) + Cosine integral from 0 to x) int_3 = (sici(np.inf)[0] - sici(p * x)[0]) ** 2 t1 = 4 * x / p t2 = 2 / p ** 2 t3 = t2 / 2 res = ( t1 * quad(f1, p * x, np.inf, limit=100)[0] + t2 * int_2 - 0.25 + t3 * int_3 ) return float(res)
def fit_si(y, x0): '''Fits equidistant (=1) 1D data with integral sine.''' ### fitting function integralsine = lambda p, x: p[0] + p[1] * sici((x - p[2]) / p[3])[0] ### choose initial params pinit = (y[x0], y.ptp() / 3.7, x0, (y.argmax() - y.argmin()) / (2 * pi)) x = linspace(0, y.size - 1, y.size) si_fit = fitcurve(integralsine, x, y, pinit) return si_fit.fit()
def SI(x): nx = np.size(x) sint = np.zeros(nx) for i in range(0,nx): if math.fabs(x[i]) < 0.01: sint[i] = x[i] - x[i]**2/18.0 + x[i]**5/600.0 - x[i]**7/35280.0 else: sint[i], junk = special.sici(x[i]) return sint
def y(self, ln_k, mass): """Fourier transform of the halo profile. Using an analytic expression for the Fourier transform from White (2001). This is only valid for an NFW profile. """ k = numpy.exp(ln_k)/self._h con = self.concentration(mass) con_plus = 1.0 + con z = k*self.virial_radius(mass)/con si_z, ci_z = special.sici(z) si_cz, ci_cz = special.sici(con_plus*z) rho_km = (numpy.cos(z)*(ci_cz - ci_z) + numpy.sin(z)*(si_cz - si_z) - numpy.sin(con*z)/(con_plus*z)) mass_k = numpy.log(con_plus) - con/con_plus return rho_km/mass_k
def quad_mat(N, h): """ Compute the integration matrix. """ k = linspace(-(N - 1) / 2.0, (N - 1) / 2.0, N) sigma = sici(pi * (k - k[0]))[0] col = h / 2.0 + (h / pi) * sigma row = h / 2.0 - (h / pi) * sigma return toeplitz(col, row)
def test_sici_consistency(): # Make sure the implementation of sici for real arguments agrees # with the implementation of sici for complex arguments. # On the negative real axis Cephes drops the imaginary part in ci def sici(x): si, ci = sc.sici(x + 0j) return si.real, ci.real x = np.r_[-np.logspace(8, -30, 200), 0, np.logspace(-30, 8, 200)] si, ci = sc.sici(x) dataset = np.column_stack((x, si, ci)) FuncData(sici, dataset, 0, (1, 2), rtol=1e-12).check()
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 _p(self, K): bs, bc = sp.sici(K) return 0.5 * ((np.pi - 2 * bs) * np.sin(K) - 2 * np.cos(K) * bc)
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 sine_integral_func(x): tmp = special.sici(x) tmp2 = -np.pi/2.0 + tmp[0] return tmp2
def ci(x): return sc.sici(x)[1]
def si(x): return sc.sici(x)[0]
def _p(self, K): si, ci = sp.sici(K) return 0.25 * (2 - K * (2 * ci * np.sin(K) + np.cos(K) * (np.pi - 2 * si)))
def sici(x): si, ci = sc.sici(x + 0j) return si.real, ci.real
def calculate_rkernel(self): gd = self.gd ng_c = gd.N_c cell_cv = gd.cell_cv icell_cv = 2 * np.pi * np.linalg.inv(cell_cv) vol = np.linalg.det(cell_cv) ns = self.calc.wfs.nspins n_g = self.n_g # density on rough grid fx_g = ns * self.get_fxc_g(n_g) # local exchange kernel qc_g = (-4 * np.pi * ns / fx_g)**0.5 # cutoff functional flocal_g = qc_g**3 * fx_g / (6 * np.pi**2) # ren. x-kernel for r=r' Vlocal_g = 2 * qc_g / np.pi # ren. Hartree kernel for r=r' ng = np.prod(ng_c) # number of grid points r_vg = gd.get_grid_point_coordinates() rx_g = r_vg[0].flatten() ry_g = r_vg[1].flatten() rz_g = r_vg[2].flatten() prnt(' %d grid points and %d plane waves at the Gamma point' % (ng, self.pd.ngmax), file=self.fd) # Unit cells R_Rv = [] weight_R = [] nR_v = self.unit_cells nR = np.prod(nR_v) for i in range(-nR_v[0] + 1, nR_v[0]): for j in range(-nR_v[1] + 1, nR_v[1]): for h in range(-nR_v[2] + 1, nR_v[2]): R_Rv.append(i * cell_cv[0] + j * cell_cv[1] + h * cell_cv[2]) weight_R.append((nR_v[0] - abs(i)) * (nR_v[1] - abs(j)) * (nR_v[2] - abs(h)) / float(nR)) if nR > 1: # with more than one unit cell only the exchange kernel is # calculated on the grid. The bare Coulomb kernel is added # in PW basis and Vlocal_g only the exchange part dv = self.calc.density.gd.dv gc = (3 * dv / 4 / np.pi)**(1 / 3.) Vlocal_g -= 2 * np.pi * gc**2 / dv prnt(' Lattice point sampling: ' + '(%s x %s x %s)^2 ' % (nR_v[0], nR_v[1], nR_v[2]) + ' Reduced to %s lattice points' % len(R_Rv), file=self.fd) l_g_size = -(-ng // mpi.world.size) l_g_range = range(mpi.world.rank * l_g_size, min((mpi.world.rank+1) * l_g_size, ng)) fhxc_qsGr = {} for iq in range(len(self.ibzq_qc)): fhxc_qsGr[iq] = np.zeros((ns, len(self.pd.G2_qG[iq]), len(l_g_range)), dtype=complex) inv_error = np.seterr() np.seterr(invalid='ignore') np.seterr(divide='ignore') t0 = time() # Loop over Lattice points for i, R_v in enumerate(R_Rv): # Loop over r'. f_rr and V_rr are functions of r (dim. as r_vg[0]) if i == 1: prnt(' Finished 1 cell in %s seconds' % int(time() - t0) + ' - estimated %s seconds left' % int((len(R_Rv) - 1) * (time() - t0)), file=self.fd) self.fd.flush() if len(R_Rv) > 5: if (i+1) % (len(R_Rv) / 5 + 1) == 0: prnt(' Finished %s cells in %s seconds' % (i, int(time() - t0)) + ' - estimated %s seconds left' % int((len(R_Rv) - i) * (time() - t0) / i), file=self.fd) self.fd.flush() for g in l_g_range: rx = rx_g[g] + R_v[0] ry = ry_g[g] + R_v[1] rz = rz_g[g] + R_v[2] # |r-r'-R_i| rr = ((r_vg[0] - rx)**2 + (r_vg[1] - ry)**2 + (r_vg[2] - rz)**2)**0.5 n_av = (n_g + n_g.flatten()[g]) / 2. fx_g = ns * self.get_fxc_g(n_av, index=g) qc_g = (-4 * np.pi * ns / fx_g)**0.5 x = qc_g * rr osc_x = np.sin(x) - x*np.cos(x) f_rr = fx_g * osc_x / (2 * np.pi**2 * rr**3) if nR > 1: # include only exchange part of the kernel here V_rr = (sici(x)[0] * 2 / np.pi - 1) / rr else: # include the full kernel (also hartree part) V_rr = (sici(x)[0] * 2 / np.pi) / rr # Terms with r = r' if (np.abs(R_v) < 0.001).all(): tmp_flat = f_rr.flatten() tmp_flat[g] = flocal_g.flatten()[g] f_rr = tmp_flat.reshape(ng_c) tmp_flat = V_rr.flatten() tmp_flat[g] = Vlocal_g.flatten()[g] V_rr = tmp_flat.reshape(ng_c) del tmp_flat f_rr[np.where(n_av < self.density_cut)] = 0.0 V_rr[np.where(n_av < self.density_cut)] = 0.0 f_rr *= weight_R[i] V_rr *= weight_R[i] # r-r'-R_i r_r = np.array([r_vg[0] - rx, r_vg[1] - ry, r_vg[2] - rz]) # Fourier transform of r for iq, q in enumerate(self.ibzq_qc): q_v = np.dot(q, icell_cv) e_q = np.exp(-1j * gemmdot(q_v, r_r, beta=0.0)) f_q = self.pd.fft((f_rr + V_rr) * e_q, iq) * vol / ng fhxc_qsGr[iq][0, :, g - l_g_range[0]] += f_q if ns == 2: f_q = self.pd.fft(V_rr * e_q, iq) * vol / ng fhxc_qsGr[iq][1, :, g - l_g_range[0]] += f_q mpi.world.barrier() np.seterr(**inv_error) for iq, q in enumerate(self.ibzq_qc): npw = len(self.pd.G2_qG[iq]) fhxc_sGsG = np.zeros((ns * npw, ns * npw), complex) l_pw_size = -(-npw // mpi.world.size) # parallelize over PW below l_pw_range = range(mpi.world.rank * l_pw_size, min((mpi.world.rank + 1) * l_pw_size, npw)) if mpi.world.size > 1: # redistribute grid and plane waves in fhxc_qsGr[iq] bg1 = BlacsGrid(mpi.world, 1, mpi.world.size) bg2 = BlacsGrid(mpi.world, mpi.world.size, 1) bd1 = bg1.new_descriptor(npw, ng, npw, - (-ng / mpi.world.size)) bd2 = bg2.new_descriptor(npw, ng, -(-npw / mpi.world.size), ng) fhxc_Glr = np.zeros((len(l_pw_range), ng), dtype=complex) if ns == 2: Koff_Glr = np.zeros((len(l_pw_range), ng), dtype=complex) r = Redistributor(bg1.comm, bd1, bd2) r.redistribute(fhxc_qsGr[iq][0], fhxc_Glr, npw, ng) if ns == 2: r.redistribute(fhxc_qsGr[iq][1], Koff_Glr, npw, ng) else: fhxc_Glr = fhxc_qsGr[iq][0] if ns == 2: Koff_Glr = fhxc_qsGr[iq][1] # Fourier transform of r' for iG in range(len(l_pw_range)): f_g = fhxc_Glr[iG].reshape(ng_c) f_G = self.pd.fft(f_g.conj(), iq) * vol / ng fhxc_sGsG[l_pw_range[0] + iG, :npw] = f_G.conj() if ns == 2: v_g = Koff_Glr[iG].reshape(ng_c) v_G = self.pd.fft(v_g.conj(), iq) * vol / ng fhxc_sGsG[npw + l_pw_range[0] + iG, :npw] = v_G.conj() if ns == 2: # f_00 = f_11 and f_01 = f_10 fhxc_sGsG[:npw, npw:] = fhxc_sGsG[npw:, :npw] fhxc_sGsG[npw:, npw:] = fhxc_sGsG[:npw, :npw] mpi.world.sum(fhxc_sGsG) fhxc_sGsG /= vol if mpi.rank == 0: w = Writer('fhxc_%s_%s_%s_%s.gpw' % (self.tag, self.xc, self.ecut, iq)) w.dimension('sG', ns * npw) w.add('fhxc_sGsG', ('sG', 'sG'), dtype=complex) if nR > 1: # add Hartree kernel evaluated in PW basis Gq2_G = self.pd.G2_qG[iq] if (q == 0).all(): Gq2_G[0] = 1. vq_G = 4 * np.pi / Gq2_G fhxc_sGsG += np.tile(np.eye(npw) * vq_G, (ns, ns)) w.fill(fhxc_sGsG) w.close() mpi.world.barrier() prnt(file=self.fd)
def _p(self, K, c=None): bs, bc = sp.sici(K) asi, ac = sp.sici((1 + c) * K) return (np.sin(K) * (asi - bs) - np.sin(c * K) / ((1 + c) * K) + np.cos(K) * (ac - bc))
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