def _FiveDelta2g_1(xyzs, fft='pyfftw', Ngrid=360): ''' calculate first part of (2 ell + 1) * delta_2 (Scoccimarro 2015 Eq. 20) More specific this function calculates delta_2 = 15/2 (kx^2 Qxx + ky^2 Qyy + kz^2 Qzz) ''' # Qxx, Qyy, Qzz (Scoccimarro 2015 Eq. 19) ifft_Qii = [] for i in range(3): _delta = np.zeros([2 * Ngrid, Ngrid, Ngrid], dtype=np.float32, order='F') # order is reversed. check this carefully fEstimate.assign_quad(xyzs, _delta, kf_ks, i + 1, i + 1, 0, 0, N, Ngrid) ifft_delta = _FFT(_delta, fft=fft, Ngrid=Ngrid) # run FFT fEstimate.fcomb(ifft_delta, N, Ngrid) # combine ifft_Qii.append(ifft_delta[:Ngrid // 2 + 1, :, :]) fEstimate.FiveDelta2g_1(ifft_Qii[0], ifft_Qii[1], ifft_Qii[2], Ngrid) return ifft_Qii[0]
def _FiveDelta2g_2(xyzs, dcg, dcgxx, fft='pyfftw', Ngrid=360): ''' calculate second part of (2 ell + 1) x delta_2 (Scoccimarro 2015 Eq. 20) = 5 x delta_2 ''' # Qxx, Qyy, Qzz (Scoccimarro 2015 Eq. 19) ifft_Qij = [] for i, j in zip([1, 2, 3], [2, 3, 1]): _delta = np.zeros([2 * Ngrid, Ngrid, Ngrid], dtype=np.float32, order='F') # order is reversed. check this carefully fEstimate.assign_quad(xyzs, _delta, kf_ks, i, j, 0, 0, N, Ngrid) ifft_delta = _FFT(_delta, fft=fft, Ngrid=Ngrid) # run FFT fEstimate.fcomb(ifft_delta, N, Ngrid) # combine ifft_Qij.append(ifft_delta[:Ngrid // 2 + 1, :, :]) fEstimate.FiveDelta2g_2(dcg, dcgxx, ifft_Qii[0], ifft_Qii[1], ifft_Qii[2], Ngrid) return dcgxx
def FFTperiodic(xyz, w=None, Lbox=2600., Ngrid=360, fft='pyfftw', silent=True): ''' Place galaxies/halos/particles in a periodic box onto a grid to estimate the density field and FFT it. This function wraps some of the functions in estimator.f and does the same thing as roman's zmapFFTil4_aniso_gen.f :param xyz: 3 x N dimensional array :param Lbox: (default: 2600.) Box size :param Ngrid: (default: 360) grid size :param fft: (default: 'pyfftw') determines which fftw version to use. Options are 'pyfftw' and 'fortran'. :param silent: (default: True) if not silent then it'll output stuff ''' kf_ks = np.float32(float(Ngrid) / Lbox) N = np.int32(xyz.shape[1]) # number of objects if w is None: w = np.ones(N) # position of galaxies (checked with fortran) xyzs = np.zeros([3, N], dtype=np.float32, order='F') xyzs[0, :] = np.clip(xyz[0, :], 0., Lbox * (1. - 1e-6)) xyzs[1, :] = np.clip(xyz[1, :], 0., Lbox * (1. - 1e-6)) xyzs[2, :] = np.clip(xyz[2, :], 0., Lbox * (1. - 1e-6)) if not silent: print('%i positions, Ntot=%.f' % (N, np.sum(w))) ws = np.zeros(N, dtype=np.float32, order='F') ws = w # assign galaxies to grid (checked with fortran) _delta = np.zeros([2 * Ngrid, Ngrid, Ngrid], dtype=np.float32, order='F') # even indices (real) odd (complex) # the order is reversed. Don't touch it!!! fEstimate.assign_quad(xyzs, ws, _delta, kf_ks, 0, 0, 0, 0, N, Ngrid) print(_delta[:5, :5, :5]) ifft_delta = _FFT(_delta, fft=fft, Ngrid=Ngrid, silent=silent) if not silent: print('position grid FFTed') # combine fields fEstimate.fcomb_periodic(ifft_delta, np.sum(w), Ngrid) if not silent: print('fcomb complete') return ifft_delta[:Ngrid // 2 + 1, :, :]
def FFT_survey(radecz, w=None, Lbox=2600., Ngrid=360, cosmo=None, fft='pyfftw', silent=True): ''' Put galaxies from a survey onto a grid and FFT it. This function wraps some of the functions in estimator.f and does the same thing as roman's zmapFFTil4_aniso_gen.f :param radecz: 3 x N dimensional array that specify the [ra, dec, z] :parapm w: (default: None) N dimensional array that specifies the weight. :param Lbox: (default: 2600.) Box size :param Ngrid: (default: 360) grid size :param cosmo: (default: None) astropy.cosmology objec that specifies the cosmology for converting RA, Dec, z to cartesian coordinates. :param fft: (default: 'pyfftw') determines which fftw version to use. Options are 'pyfftw' and 'fortran'. :param silent: (default: True) if not silent then it'll output stuff notes ----- ''' kf_ks = np.float32(float(Ngrid) / Lbox) N = np.int32(xyz.shape[1]) # number of objects # default cosmology if cosmo is None: cosmo = FlatLambdaCDM(H0=67.6, Om0=0.31) if w is None: w = np.ones(N) # convert ra, dec, z to cartesian coordinates xyz = UT.radecz_to_cartesian(radecz, cosmo=cosmo) if not silent: print([ '%.1f < %s < %.1f\n' % (mi, _axis, ma) for _axis, mi, ma in zip(['x', 'y', 'z'], np.min(xyz, axis=1), np.max(xyz, axis=1)) ]) # position of galaxies (checked with fortran) xyzs = np.zeros([3, N], dtype=np.float32, order='F') xyzs[0, :] = np.clip(xyz[0, :], 0., Lbox * (1. - 1e-6)) xyzs[1, :] = np.clip(xyz[1, :], 0., Lbox * (1. - 1e-6)) xyzs[2, :] = np.clip(xyz[2, :], 0., Lbox * (1. - 1e-6)) if not silent: print('%i positions' % N) # calculate I10,I12d,I22,I13d,I23,I33 _delta = np.zeros([2 * Ngrid, Ngrid, Ngrid], dtype=np.float32, order='F') fEstimate.assign_quad(xyzs, w, _delta, kf_ks, 0, 0, 0, 0, N, Ngrid) # assign to grid ifft_delta = _FFT(_delta, fft=fft, Ngrid=Ngrid, silent=silent) # run FFT fEstimate.fcomb(ifft_delta, N, Ngrid) # combine delta0 = ifft_delta[:Ngrid // 2 + 1, :, :] if not silent: print('delta_0(k) complete') # calculate delta2 five_delta2 = _FiveDelta2g_1(xyzs, fft=fft, Ngrid=Ngrid) five_delta2 = _FiveDelta2g_1(xyzs, delta0, five_delta2, fft=fft, Ngrid=Ngrid) # calculat reweighted fields w = w**2 _delta = np.zeros([2 * Ngrid, Ngrid, Ngrid], dtype=np.float32, order='F') fEstimate.assign_quad(xyzs, w, _delta, kf_ks, 0, 0, 0, 0, N, Ngrid) # assign to grid ifft_delta = _FFT(_delta, fft=fft, Ngrid=Ngrid, silent=silent) # run FFT fEstimate.fcomb(ifft_delta, N, Ngrid) # combine delta_w = ifft_delta[:Ngrid // 2 + 1, :, :] return delta0, five_delta2, delta_w