def test_alternative(s, nu, k, N, h): """Test alternative hankel definition.""" ht1 = HankelTransform(nu=nu, N=N, h=h) ht2 = HankelTransform(nu=nu, N=N, h=h, alt=True) ft1 = ht1.transform(lambda r: r**s, k, False, False) ft2 = ht2.transform(lambda r: r**(s + 0.5), k, False, False) / k**0.5 print("Numerical Results: ", ft1, " and ", ft2) assert np.isclose(ft1, ft2, rtol=1e-3)
def Cl_to_wtheta(nz, table_l, table_Cl, theta, path, nu=0, N=500, h=0.005): assert isinstance(nz, int), 'Invalid nz: {}. Must be an integer'.format(nz) import os from hankel import HankelTransform as HT import numpy as np from scipy.interpolate import UnivariateSpline header = '{:<25s}'.format('# r (deg)') for i in range(nz): header += '{:<25s}'.format('w_{}'.format(i)) ht = HT(nu=nu, N=N, h=h) w = np.empty((nz, theta.size)) for i in range(nz): # Fit Cl's with Spline Cl = UnivariateSpline(table_l, table_Cl[i], s=0, k=1) # Do the Hankel Transform to get the correlation function for j, thetai in zip(range(theta.size), np.deg2rad(theta)): f = lambda x: (x * Cl(x / thetai)) / (2. * np.pi * np.power( thetai, 2)) w[i, j] = ht.transform(f)[0] np.savetxt(path, np.vstack((theta, w)).T, fmt='%-25.18e', header=header, comments='') return w
def test_k_zero(nu, alt): """Testing k=0.""" threshold = -0.5 if alt else 0 ht = HankelTransform(nu=nu, N=50, h=1e-3, alt=alt) ans = ht.transform(lambda r: np.exp(-(r**2) / 2), 0, False, False) print("Numerical Results: ", ans) if nu < threshold: assert np.isnan(ans) elif nu > threshold: assert np.isclose(ans, 0, rtol=1e-3) else: assert np.isclose(ans, 1, rtol=1e-3)
def test_powerlaw(s, nu, k, N, h): """ Test f(r) = 1/r, nu=0 """ ht = HankelTransform(nu=nu, N=N, h=h) ans = ht.transform(lambda x: x ** s, k, False, False) if nu - s <= 0 and (nu - s) % 2 == 0: raise Exception("Can't have a negative integer for gamma") anl = 2 ** (s + 1) * gamma(0.5 * (2 + nu + s)) / k ** (s + 2) / gamma(0.5 * (nu - s)) print("Numerical Result: ", ans, " (required %s)" % anl) assert np.isclose(ans, anl, rtol=1e-3)
class SeeingApertureMTF: """ This is the class that generates the effective aperture for a given Fried parameter and can also populate it using the model assuming that the Earth's atmosphere can be modelled as a medium with smoothly varying turbulence. Parameters ---------- wavel : float The wavelength of light in Angstroms. r0 : float The Fried parameter in m. pxScale : float The size of one detector pixel in arcseconds on the observed object. air : bool, optional Whether or not the provided wavelength is air wavelength. If not then the wavelength is converted from vacuum value. Default is False. """ def __init__(self, wavel, r0, pxScale, air=False): if air: self.wavel = wavel * 1e-10 else: self.wavel = vac_to_air(wavel << u.Angstrom).value * 1e-10 self.r0 = r0 self.pxScale = pxScale self.resolution = 0.98 * self.wavel / self.r0 * 206265 # resolution of the image after being imaged through seeing self.diameter = int(self.resolution / self.pxScale) # diameter of PSF in pixels self.psf = np.zeros(shape=(int(self.diameter), int(self.diameter))) self.pxm = np.linspace( 1.75, 880, int(880 / 1.75) + 1 ) # 1.75 is the size of one pixel in metres and 880 is the size of 840 pixels in metres and the int(880/1.75)+1 is the number of pixels in the field-of-view of 840 pixels, this is an average field-of-view size in pixels with higher field-of-views not adding much to the terms self.modtf = self.mtf(self.wavel, self.r0) self.ht = HankelTransform(nu=0, h=0.05, N=62) self.psf1d = self.ht.transform(self.modtf, self.pxm, ret_err=False) for j in range(self.psf.shape[0]): for i in range(self.psf.shape[1]): idx = int( np.linalg.norm((j - self.psf.shape[0] // 2, i - self.psf.shape[1] // 2))) self.psf[j, i] = self.psf1d[idx] self.psf /= self.psf.sum() @staticmethod def mtf(wavel, r0): return lambda x: np.exp(-(6.88 / 2.0) * (wavel * x / (2 * np.pi * r0))**(5 / 3))
def test_powerlaw(s, nu, k, N, h): """ Test f(r) = 1/r, nu=0 """ ht = HankelTransform(nu=nu, N=N, h=h) ans = ht.transform(lambda x: x**s, k, False, False) if nu - s <= 0 and (nu - s) % 2 == 0: raise Exception("Can't have a negative integer for gamma") anl = (2**(s + 1) * gamma(0.5 * (2 + nu + s)) / k**(s + 2) / gamma(0.5 * (nu - s))) print("Numerical Result: ", ans, " (required %s)" % anl) assert np.isclose(ans, anl, rtol=1e-3)
def H_3(x,n,mu,dia): y = np.pi * mu / 6.0 lam1 = (1 + 2 * y) ** 2 / ((1.0 - y) ** 4) lam2 = - (1 + y / 2.0) ** 2 / ((1.0 - y) ** 4) x = x/dia C3 = lambda x: -(lam1 * y * x ** 3 / 2.0 + 6 * y * lam2 * x + lam1) if (1 >= x.any() >= 0) else 0 C2 = [] for x2 in x: C2.append(C3(x2)) h = HankelTransform(nu=0, N=1000, h=0.005) Ck_3 = h.transform(C3, k, ret_err=False) Hk_3 = Ck_3 / (1 - n * Ck_3) #Hk_3 = spline(k, Hk_3) # Define a spline to approximate transform #Hx_3 = h.transform(Hk_3, x, False, inverse=True) #Fk = ht.transform(C3, k, ret_err=False) #Ck_3 = fft(C2) return Hk_3
def FT3D(self, k, cf, R=None, Rmin=None, Rmax=None, epsabs=1e-12, epsrel=1e-12, limit=500, split_by_scale=False, method='clenshaw-curtis', use_pb=False, suppression=np.inf): """ This is nearly identical to the inverse transform function above, I just got tired of having to remember to swap meanings of the k and R variables. Sometimes clarity is better than minimizing redundancy. """ assert type(k) == np.ndarray if (type(cf) == FunctionType) or isinstance(cf, interp1d) \ or isinstance(cf, Akima1DInterpolator): R = cf.x elif type(cf) == np.ndarray: # Setup interpolant assert R is not None, "Must supply R vector as well!" #if interpolant == 'akima': # ps = Akima1DInterpolator(k, ps) #elif interpolant == 'cubic': cf = interp1d(np.log(R), cf, kind='cubic', assume_sorted=True, bounds_error=False, fill_value=0.0) else: raise ValueError('Do not understand type of `ps`.') if Rmin is None: Rmin = R.min() if Rmax is None: Rmax = R.max() norm = 1. / cf(np.log(Rmin)) if method == 'ogata': assert have_hankel, "hankel package required for this!" integrand = lambda RR: four_pi * R**2 * norm * cf(np.log(RR)) ht = HankelTransform(nu=0, N=k.size, h=0.1) #integrand = lambda kk: ps(np.log(kk)) * norm #ht = SymmetricFourierTransform(3, N=k.size, h=0.001) #print(ht.integrate(integrand)) ps = ht.transform(integrand, k=k, ret_err=False, inverse=False) / norm return ps ## # Optional progress bar ## pb = ProgressBar(R.size, use=self.pf['progress_bar'] * use_pb, name='cf(R)->ps(k)') # Loop over k and perform integral ps = np.zeros_like(k) for i, kk in enumerate(k): if not pb.has_pb: pb.start() pb.update(i) if method == 'clenshaw-curtis': # Leave sin(k*R) out -- that's the 'weight' for scipy. # Note the minus sign. integrand = lambda RR: norm * four_pi * RR**2 * cf(np.log(RR)) \ * np.exp(-kk * RR / suppression) / kk / RR if split_by_scale: Rcri = np.exp(cf.x[np.argmin( np.abs(np.exp(cf.x) - 1. / kk))]) # Integral over small k is easy lowR = np.exp(cf.x) <= Rcri Rlow = np.exp(cf.x[lowR == 1]) clow = cf.y[lowR == 1] sinc = np.sin(kk * Rlow) / Rlow / kk integ = norm * four_pi * Rlow**2 * clow * sinc \ * np.exp(-kk * Rlow / suppression) ps[i] = np.trapz(integ * Rlow, x=np.log(Rlow)) / norm Rstart = Rcri #if lowR.sum() < 1000 and lowR.sum() % 100 == 0: # import matplotlib.pyplot as pl # # pl.figure(2) # # sinc = np.sin(kk * R) / kk / R # pl.loglog(R, integrand(R) * sinc, color='k') # pl.loglog([Rcri]*2, [1e-4, 1e4], color='y') # raw_input('<enter>') else: Rstart = Rmin # Use 'chebmo' to save Chebyshev moments and pass to next integral? ps[i] += quad(integrand, Rstart, Rmax, epsrel=epsrel, epsabs=epsabs, limit=limit, weight='sin', wvar=kk)[0] / norm else: raise NotImplemented('help') pb.finish() # return np.abs(ps)
def InverseFT3D(self, R, ps, k=None, kmin=None, kmax=None, epsabs=1e-12, epsrel=1e-12, limit=500, split_by_scale=False, method='clenshaw-curtis', use_pb=False, suppression=np.inf): """ Take a power spectrum and perform the inverse (3-D) FT to recover a correlation function. """ assert type(R) == np.ndarray if (type(ps) == FunctionType) or isinstance(ps, interp1d) \ or isinstance(ps, Akima1DInterpolator): k = ps.x elif type(ps) == np.ndarray: # Setup interpolant assert k is not None, "Must supply k vector as well!" #if interpolant == 'akima': # ps = Akima1DInterpolator(k, ps) #elif interpolant == 'cubic': ps = interp1d(np.log(k), ps, kind='cubic', assume_sorted=True, bounds_error=False, fill_value=0.0) #_ps = interp1d(np.log(k), np.log(ps), kind='cubic', assume_sorted=True, # bounds_error=False, fill_value=-np.inf) # #ps = lambda k: np.exp(_ps.__call__(np.log(k))) else: raise ValueError('Do not understand type of `ps`.') if kmin is None: kmin = k.min() if kmax is None: kmax = k.max() norm = 1. / ps(np.log(kmax)) ## # Use Steven Murray's `hankel` package to do the transform ## if method == 'ogata': assert have_hankel, "hankel package required for this!" integrand = lambda kk: four_pi * kk**2 * norm * ps(np.log(kk)) \ * np.exp(-kk * R / suppression) ht = HankelTransform(nu=0, N=k.size, h=0.001) #integrand = lambda kk: ps(np.log(kk)) * norm #ht = SymmetricFourierTransform(3, N=k.size, h=0.001) #print(ht.integrate(integrand)) cf = ht.transform(integrand, k=R, ret_err=False, inverse=True) / norm return cf / (2. * np.pi)**3 else: pass # Otherwise, do it by-hand. ## # Optional progress bar ## pb = ProgressBar(R.size, use=self.pf['progress_bar'] * use_pb, name='ps(k)->cf(R)') # Loop over R and perform integral cf = np.zeros_like(R) for i, RR in enumerate(R): if not pb.has_pb: pb.start() pb.update(i) # Leave sin(k*R) out -- that's the 'weight' for scipy. integrand = lambda kk: norm * four_pi * kk**2 * ps(np.log(kk)) \ * np.exp(-kk * RR / suppression) / kk / RR if method == 'clenshaw-curtis': if split_by_scale: kcri = np.exp(ps.x[np.argmin( np.abs(np.exp(ps.x) - 1. / RR))]) # Integral over small k is easy lowk = np.exp(ps.x) <= kcri klow = np.exp(ps.x[lowk == 1]) plow = ps.y[lowk == 1] sinc = np.sin(RR * klow) / klow / RR integ = norm * four_pi * klow**2 * plow * sinc \ * np.exp(-klow * RR / suppression) cf[i] = np.trapz(integ * klow, x=np.log(klow)) / norm kstart = kcri #print(RR, 1. / RR, kcri, lowk.sum(), ps.x.size - lowk.sum()) # #if lowk.sum() < 1000 and lowk.sum() % 100 == 0: # import matplotlib.pyplot as pl # # pl.figure(2) # # sinc = np.sin(RR * k) / k / RR # pl.loglog(k, integrand(k) * sinc, color='k') # pl.loglog([kcri]*2, [1e-4, 1e4], color='y') # raw_input('<enter>') else: kstart = kmin # Add in the wiggly part cf[i] += quad(integrand, kstart, kmax, epsrel=epsrel, epsabs=epsabs, limit=limit, weight='sin', wvar=RR)[0] / norm else: raise NotImplemented('help') pb.finish() # Our FT convention cf /= (2 * np.pi)**3 return cf
for i, snapshot in enumerate([85, 79, 73, 68]): print i, snapshot # Load the measured correlation function gi=np.loadtxt('/Users/hattifattener/Documents/ias/mbii/2pt/ns300_nd1000/v10/snapshot%d/fiducial/GIplus_proj_corr_00.txt'%snapshot).T ii=np.loadtxt('/Users/hattifattener/Documents/ias/mbii/2pt/ns300_nd1000/v10/snapshot%d/fiducial/IIplus_proj_corr_00.txt'%snapshot).T # Initialise the transform ht4 = HankelTransform(nu=2, N=12000, h=0.005) ht4 = HankelTransform(nu=4, N=12000, h=0.005) spline = Spline(gi[0], gi[1], k=1) K = lambda x : spline(x) splineii = Spline(ii[0], ii[1], k=1) Kii = lambda x : splineii(x) # Evaluate the integral repeatedly at each of a set of k values pk = np.array([ht4.transform(K, k0)[0] for k0 in k ]) pkII = np.array([ 0.5 * (ht4.transform(Kii, k0)[0] + ht4.transform(Kii, k0)[0]) for k0 in k ]) # Store the power spectrum for this redshift PgI[snapshot] = -1 * pk PII[snapshot] = pkII plt.plot(k, pk, color=colours[i], label='$z=%3.2f$'%redshift[snapshot]) plt.plot(k, pkII, color=colours[i], ls='--') np.savetxt('pgI-massive_black_ii-snapshot%d.txt'%snapshot, [k,pk]) np.savetxt('pII-massive_black_ii-snapshot%d.txt'%snapshot, [k,pkII]) plt.xlabel('Wavenumber $k$ / $h^{-1}$', fontsize=16) plt.ylabel(r'$P_\mathrm{\delta_g I}(k)$', fontsize=16) plt.xscale('log') plt.yscale('log')
def test_equivalence_of_integrate_and_transform(): ht = HankelTransform(N=50) intg = ht.integrate(lambda x: 1, False) tr = ht.transform(lambda x: 1.0 / x, ret_err=False) assert intg == tr
def test_k_scalar(): k = 1 ht = HankelTransform(N=50) res = ht.transform(lambda x: 1.0 / x, k, False) assert np.isscalar(res)
def test_k_array(): k = np.logspace(-3, 3, 10) ht = HankelTransform(N=50) res = ht.transform(lambda x: 1.0 / x, k, False) assert len(res) == 10
#!/usr/bin/env python import sys, os import numpy as np import pylab as py from hankel import HankelTransform from scipy.special import jv as bessel from scipy.integrate import quad, quadrature, fixed_quad BT = np.linspace(0, 10, 100) W = lambda bT: np.exp(-0.5 * bT**2) qT = 2.0 integrand = lambda bT: bT * bessel(0, bT * qT) * W(bT) tgral = quad(integrand, 1e-4, np.inf)[0] print tgral f = lambda x: x * W(x / qT) #h = HankelTransform(nu=0,N=120,h=0.03) h = HankelTransform(nu=0, N=120, h=0.003) print h.transform(f, ret_err=False)[0] / qT**2 #f = lambda x: 1 #Define the input function f(x) #h = HankelTransform(nu=0,N=120,h=0.03) #Create the HankelTransform instance #print h.transform(f)
# P2D = interp1d(ls, refs, kind='cubic') spl = Spline(np.log(ths), np.log(refs), k=1) def P2D(x): return np.exp(spl(np.log(x))) # Xi+ htp = HankelTransform( nu=0, # The order of the bessel function N=120000, # Number of steps in the integration h=0.01 # Proxy for "size" of steps in integration ) xip = htp.transform(P2D, ths, ret_err=False) # Xi- htm = HankelTransform( nu=4, # The order of the bessel function N=120000, # Number of steps in the integration h=0.01 # Proxy for "size" of steps in integration ) xim = htm.transform(P2D, ths, ret_err=False) plt.figure(1).set_size_inches((8, 8), forward=False) plt.plot(thsarcmin, [abs(xip[i] * 2 * np.pi - refs1[i]) / refs1[i] for i in range(nth)]) plt.title("Variation of $\\xi_+$ changing modes number, lref={0}".format(ref)) plt.xlabel("$\\theta$ (arcmin)")
def test_equivalence_of_integrate_and_transform(): ht = HankelTransform(N=50) int = ht.integrate(lambda x: 1, False) tr = ht.transform(lambda x: 1. / x, ret_err=False) assert int == tr
def test_k_scalar(): k = 1 ht = HankelTransform(N=50) res = ht.transform(lambda x: 1. / x, k, False) assert np.isscalar(res)
def test_k_array(): k = np.logspace(-3, 3, 10) ht = HankelTransform(N=50) res = ht.transform(lambda x: 1. / x, k, False) assert len(res) == 10