def test_plain_wcs(self): # Test area and box for a small Cartesian geometry shape,wcs = enmap.geometry(res=np.deg2rad(1./60.),shape=(600,600),pos=(0,0),proj='plain') box = np.rad2deg(enmap.box(shape,wcs)) area = np.rad2deg(np.rad2deg(enmap.area(shape,wcs))) assert np.all(np.isclose(box,np.array([[-5,-5],[5,5]]))) assert np.isclose(area,100.) # and for an artifical Cartesian geometry with area>4pi shape,wcs = enmap.geometry(res=np.deg2rad(10),shape=(100,100),pos=(0,0),proj='plain') box = np.rad2deg(enmap.box(shape,wcs)) area = np.rad2deg(np.rad2deg(enmap.area(shape,wcs))) assert np.all(np.isclose(box,np.array([[-500,-500],[500,500]]))) assert np.isclose(area,1000000)
def test_area(self): """Test that map area is computed accurately.""" test_patches = [] # Small CAR patch DELT = 0.01 patch = Patch.centered_at(-52., -38., 12. + DELT, 12.0 + DELT) shape, w = enmap.geometry(pos=patch.pos(), res=DELT*DEG, proj='car', ref=(0, 0)) exact_area = (np.dot(patch.ra_range*DEG, [-1,1]) * np.dot(np.sin(patch.dec_range*DEG), [1,-1])) test_patches.append((shape, w, exact_area)) # Full sky CAR patch shape, w = enmap.fullsky_geometry(res=0.01*DEG, proj='car') exact_area = 4*np.pi test_patches.append((shape, w, exact_area)) # Small ZEA patch at pole shape, w = enmap.geometry(pos=[90*DEG,0], res=DELT*DEG, proj='zea', shape=[100,100]) exact_area = 1*DEG**2 test_patches.append((shape, w, exact_area)) for shape, w, exact_area in test_patches: ratio = enmap.area(shape, w)/exact_area print(ratio) assert(abs(ratio-1) < 1e-6)
def wfactor(n, mask, sht=True, pmap=None, equal_area=False): """ Approximate correction to an n-point function for the loss of power due to the application of a mask. For an n-point function using SHTs, this is the ratio of area weighted by the nth power of the mask to the full sky area 4 pi. This simplifies to mean(mask**n) for equal area pixelizations like healpix. For SHTs on CAR, it is sum(mask**n * pixel_area_map) / 4pi. When using FFTs, it is the area weighted by the nth power normalized to the area of the map. This also simplifies to mean(mask**n) for equal area pixels. For CAR, it is sum(mask**n * pixel_area_map) / sum(pixel_area_map). If not, it does an expensive calculation of the map of pixel areas. If this has been pre-calculated, it can be provided as the pmap argument. """ assert mask.ndim == 1 or mask.ndim == 2 if pmap is None: if equal_area: npix = mask.size pmap = 4 * np.pi / npix if sht else enmap.area( mask.shape, mask.wcs) / npix else: pmap = enmap.pixsizemap(mask.shape, mask.wcs) return np.sum((mask**n) * pmap) / np.pi / 4. if sht else np.sum( (mask**n) * pmap) / np.sum(pmap)
def test_fullsky_geometry(self): # Tests whether number of pixels and area of a full-sky 0.5 arcminute resolution map are correct print("Testing full sky geometry...") test_res_arcmin = 0.5 shape,wcs = enmap.fullsky_geometry(res=np.deg2rad(test_res_arcmin/60.),proj='car') assert shape[0]==21601 and shape[1]==43200 assert abs(enmap.area(shape,wcs) - 4*np.pi) < 1e-6
def _counts(self): cts = self.counts.copy() cts[self.mask < 0.9] = np.nan self.ngals = np.nansum(cts) self.nmean = np.nanmean(cts) if self.curved: area_sqdeg = 4. * np.pi * (180. / np.pi)**2. else: area_sqdeg = enmap.area(self.shape, self.wcs) * (180. / np.pi)**2. self.frac = self.mask.sum() * 1. / self.mask.size self.area_sqdeg = self.frac * area_sqdeg self.ngal_per_arcminsq = self.ngals / (self.area_sqdeg * 60. * 60.)
def fcov_to_rcorr(shape,wcs,p2d,N): """Convert a 2D PS into a pix-pix covariance """ ncomp = p2d.shape[0] p2d *= np.prod(shape[-2:])/enmap.area(shape,wcs) ocorr = enmap.zeros((ncomp,ncomp,N*N,N*N),wcs) for i in range(ncomp): for j in range(i,ncomp): dcorr = ps2d_to_mat(p2d[i,j].copy(), N).reshape((N*N,N*N)) ocorr[i,j] = dcorr.copy() if i!=j: ocorr[j,i] = dcorr.copy() return ocorr
def test_fullsky_geometry(): # Tests whether number of pixels and area of a full-sky 0.5 arcminute resolution map are correct test_res_arcmin = 0.5 shape,wcs = enmap.fullsky_geometry(res=np.deg2rad(test_res_arcmin/60.),proj='car') assert shape[0]==21601 and shape[1]==43200 assert 50000 < (enmap.area(shape,wcs)*(180./np.pi)**2.) < 51000
def get_poisson_srcs_alms(self, set_idx, sim_num, patch, alm_shape, oshape, owcs): def deltaTOverTcmbToJyPerSr(freqGHz, T0=2.726): """ @brief the function name is self-eplanatory @return the converstion factor stolen from Flipper -- van engelen """ kB = 1.380658e-16 h = 6.6260755e-27 c = 29979245800. nu = freqGHz * 1.e9 x = h * nu / (kB * T0) cNu = 2 * (kB * T0)**3 / (h**2 * c**2) * x**4 / (4 * (np.sinh(x / 2.))**2) cNu *= 1e23 return cNu TCMB_uk = 2.72e6 if oshape[0] > 3: #then this is a multichroic array, and sadly we only have this at 150 GHz for now raise Exception('get_poisson_srcs_alms only implemented for 150 GHz so far ' \ + '(that is the model we currently have for radio sources) ') else: freq_ghz = 148 #ideally this RNG stuff would be defined in a central place to #avoid RNG collisions. Old version is currently commented out at top of #simgen.py templ = self.get_template(patch, shape=oshape, wcs=owcs) templ[:] = 0 seed = seedgen.get_poisson_seed(set_idx, sim_num) np.random.seed(seed=seed) #Wasn't sure how to codify this stuff outside this routine - hardcoded for now S_min_Jy = .001 S_max_Jy = .015 tucci = np.loadtxt( os.path.join(os.path.dirname(os.path.abspath(__file__)), '../data/ns_148GHz_modC2Ex.dat')) S = tucci[:, 0] dS = S[1:] - S[0:-1] dS = np.append(dS, [0.]) dNdS = tucci[:, 1] mean_numbers_per_patch = dNdS * enmap.area(templ.shape, templ.wcs) * dS numbers_per_fluxbin = np.random.poisson(mean_numbers_per_patch) #note pixel areas not constant for pixell maps pixel_areas = enmap.pixsizemap(templ.shape, templ.wcs) for si, fluxval in enumerate(S[S <= S_max_Jy]): xlocs = np.random.randint(templ.shape[-1], size=numbers_per_fluxbin[si]) ylocs = np.random.randint(templ.shape[-2], size=numbers_per_fluxbin[si]) #add the value in jy / sr, i.e. divide by the solid angle of a pixel. templ[0, ylocs, xlocs] += fluxval / pixel_areas[ylocs, xlocs] map_factor = TCMB_uk / deltaTOverTcmbToJyPerSr(freq_ghz) templ *= map_factor #GET ALMs output = curvedsky.map2alm(templ[0], lmax=hp.Alm.getlmax(alm_shape[0])) return output
def get_covariance(window, lmax, spec_name_list, ps_dict, binning_file, error_method="master", spectra=None, l_thres=None, l_toep=None, mbb_inv=None, compute_T_only=False): """Compute the covariance matrix of the power spectrum in the patch Parameters ---------- window: so_map the window function of the patch lmax: integer the maximum multipole to consider for the spectra computation spec_name_list: list the list of power spectra For example : [split0xsplit0,split0xsplit1,split1xsplit1] note that for computing the error on PS(split0xsplit1) we need PS(split0xsplit0), PS(split0xsplit1), PS(split1xsplit1) ps_dict: dict a dict containing all power spectra binning_file: text file a binning file with three columns bin low, bin high, bin mean note that either binning_file or bin_size should be provided error_method: string the method for the computation of error can be "master" or "knox" for now approx_coupling: dict mbb_inv: 2d array the inverse mode coupling matrix, not in use for 2dflat compute_T_only: boolean True to compute only T spectra """ bin_lo, bin_hi, bin_c, bin_size = pspy_utils.read_binning_file( binning_file, lmax) n_bins = len(bin_hi) fsky = enmap.area(window.data.shape, window.data.wcs) / 4. / np.pi fsky *= np.mean(window.data) cov_dict = {} if error_method == "Knox": for name in spec_name_list: m1, m2 = name.split("x") cov_dict[name] = {} for spec in spectra: X, Y = spec prefac = 1 / ((2 * bin_c + 1) * fsky * bin_size) cov_dict[name][X + Y] = np.diag( prefac * (ps_dict["%sx%s" % (m1, m1)][X + X] * ps_dict["%sx%s" % (m2, m2)][Y + Y] + ps_dict["%sx%s" % (m1, m2)][X + Y]**2)) elif error_method == "master": print("compute master error") if mbb_inv is None: raise ValueError("Missing 'mbb_inv' argument") if not compute_T_only: mbb_inv = mbb_inv["spin0xspin0"] coupling_dict = so_cov.cov_coupling_spin0(window, lmax, niter=0, l_thres=l_thres, l_toep=l_toep) coupling = so_cov.bin_mat(coupling_dict["TaTcTbTd"], binning_file, lmax) for name in spec_name_list: m1, m2 = name.split("x") cov_dict[name] = {} for spec in spectra: X, Y = spec cov_dict[name][X + Y] = so_cov.symmetrize( ps_dict["%sx%s" % (m1, m1)][X + X]) * so_cov.symmetrize( ps_dict["%sx%s" % (m2, m2)][Y + Y]) cov_dict[name][X + Y] += so_cov.symmetrize( ps_dict["%sx%s" % (m1, m2)][X + Y]**2) cov_dict[name][X + Y] *= coupling cov_dict[name][X + Y] = np.dot( np.dot(mbb_inv, cov_dict[name][X + Y]), mbb_inv.T) else: cov_dict = None return cov_dict
def compute_mode_coupling(window, type, lmax, binning_file, ps_method="master", beam=None, lmax_pad=None, l_thres=None, l_toep=None, compute_T_only=False): """Compute the mode coupling corresponding the the window function Parameters ---------- window: so_map the window function of the patch type: string the type of binning, either bin Cl or bin Dl lmax : integer the maximum multipole to consider for the spectra computation binning_file: text file a binning file with three columns bin low, bin high, bin mean note that either binning_file or bin_size should be provided ps_method: string the method for the computation of the power spectrum can be "master", "pseudo", or "2dflat" for now beam: text file file describing the beam of the map, expect bl to be the second column and start at l=0 (standard is : l,bl, ...) lmax_pad: integer the maximum multipole to consider for the mcm computation (optional) lmax_pad should always be greater than lmax compute_T_only: boolean True to compute only T spectra """ bin_lo, bin_hi, bin_c, bin_size = pspy_utils.read_binning_file( binning_file, lmax) n_bins = len(bin_hi) fsky = enmap.area(window.data.shape, window.data.wcs) / 4. / np.pi fsky *= np.mean(window.data) if beam is not None: beam_data = np.loadtxt(beam) if compute_T_only: beam = beam_data[:, 1] else: beam = (beam_data[:, 1], beam_data[:, 1]) if compute_T_only: if ps_method == "master": mbb_inv, Bbl = so_mcm.mcm_and_bbl_spin0(window, binning_file, bl1=beam, lmax=lmax, type=type, niter=0, lmax_pad=lmax_pad, l_thres=l_thres, l_toep=l_toep) elif ps_method == "pseudo": mbb_inv = np.identity(n_bins) mbb_inv *= 1 / fsky else: window = (window, window) if ps_method == "master": print("compute master MCM") mbb_inv, Bbl = so_mcm.mcm_and_bbl_spin0and2(window, binning_file, bl1=beam, lmax=lmax, type=type, niter=0, lmax_pad=lmax_pad, l_thres=l_thres, l_toep=l_toep) elif ps_method == "pseudo": mbb_inv = {} spin_list = ["spin0xspin0", "spin0xspin2", "spin2xspin0"] for spin in spin_list: mbb_inv[spin] = np.identity(n_bins) mbb_inv[spin] *= 1 / fsky mbb_inv["spin2xspin2"] = np.identity(4 * n_bins) mbb_inv["spin2xspin2"] *= 1 / fsky if ps_method == "2dflat": mbb_inv = None return mbb_inv
def getActpolNoiseSim(noiseSeed, psa, noisePsdDir, freqs, verbose=True, useCovSqrt=True, killFactor=30., fillValue=0., noiseDiagsOnly=False, splitWanted=None): #return array of T, Q, U #to-do: these are currently using numpy.FFT and are slow; switch to FFTW if installed. #Could also have an alternative version of this using enlib tools. if useCovSqrt: #in this case it was the CovSqrt's that were saved. This is based on Mat's code in orphics. if verbose: print( 'getActpolNoiseSim(): getting weight maps; assuming I for all') iqu = 'I' #FOR NOW # stackOfMaskMaps = [enmap.read_map(noisePsdDir + 'totalWeightMap' \ # + iqu + '_' + psa + '_' + freq + '_fromenlib.fits') \ # for freq in freqs ] if splitWanted is None: stackOfMaskMaps = [enmap.read_map(noisePsdDir + 'totalWeightMap'\ + iqu + '_' + psa + '_' + freq + '_fromenlib.fits') \ for freq in freqs ] else: stackOfMaskMaps = [enmap.read_map(noisePsdDir + 'weightMap_split' + str(splitWanted) \ + iqu + '_' + psa + '_' + freq + '_fromenlib.fits') \ for freq in freqs ] thisWcs = stackOfMaskMaps[0].wcs maskMaps = enmap.enmap(np.stack(stackOfMaskMaps), thisWcs) #first one is for IXI, QxQ, UXU only print("loading") if False: print('loading ' + noisePsdDir + '/bigMatrixNoisePsdsCovSqrtDiags_' + psa + '.fits HACKING') covsqrt = enmap.read_fits(noisePsdDir + '/bigMatrixNoisePsdsCovSqrtDiags_' + psa + '.fits') if False: print('loading ' + noisePsdDir + '/bigMatrixNoisePsdsCovSqrt_' + psa + '.fits') covsqrt = enmap.read_fits(noisePsdDir + '/bigMatrixNoisePsdsCovSqrt_' + psa + '.fits') if noiseDiagsOnly: print('loading ' + noisePsdDir + '/noisePsds_flattened_covSqrtDiags_' + psa + '.fits') covsqrt = enmap.read_fits(noisePsdDir + '/noisePsds_flattened_covSqrtDiags_' + psa + '.fits') elif True: print('loading ' + noisePsdDir + '/noisePsds_flattened_covSqrt_' + psa + '.fits') covsqrt = enmap.read_fits(noisePsdDir + '/noisePsds_flattened_covSqrt_' + psa + '.fits') print("loading done") if verbose: print('getActpolNoiseSim(): running map_mul to make random phases') #get the right normalization covsqrt *= np.sqrt( np.prod(covsqrt.shape[-2:]) / enmap.area(covsqrt.shape[-2:], thisWcs)) np.random.seed(noiseSeed) print("randmap") rmap = enmap.rand_gauss_harm( (covsqrt.shape[0], covsqrt.shape[-2:][0], covsqrt.shape[-2:][1]), thisWcs) print("randmap done") print("map_mul") kmap = enmap.map_mul(covsqrt, rmap) print("map_mul done") #old way: # kmapReshape = kmap.reshape((4, kmap.shape[-2:][0], kmap.shape[-2:][1])) # outMaps = enmap.ifft(kmapReshape).real # kmap /= sqrt(mask) if verbose: print('getActpolNoiseSim(): inverse transforming') print('you are transforming %d maps' % kmap.shape[0]) spin = np.repeat([0], kmap.shape[0]) print("fft") outMaps = enmap.harm2map(kmap, iau=False, spin=spin) print("fft done") #now reshape to have shape [nfreqs, 3, Ny, Nx] #The "order = 'F' (row vs. column ordering) is due to the ordering that is done #in makeNoisePsds.py for the dichroic arrays, #namely I90, Q90, U90, I150, Q150, U150. outMaps = outMaps.reshape(len(freqs), outMaps.shape[0] / len(freqs), outMaps.shape[-2], outMaps.shape[-1], order='F') for fi, freq in enumerate(freqs): #Note each frequency has its own maskmap, so this loop is important thisMaskMap = np.squeeze(maskMaps[fi]) outMaps[fi, :, :, :] /= np.sqrt(thisMaskMap) #Loop over T,Q,U. Couldn't think of clever way to vectorize this part.. for z in range(outMaps.shape[-3]): outMaps[fi, z][thisMaskMap < thisMaskMap[np.where(np.isfinite(thisMaskMap))].max() / killFactor] \ = fillValue if verbose: print('getActpolNoiseSim(): done ') return outMaps else: raise ValueError('older ways of getting the noise maps are deprecated')
def get_covariance( window, lmax, spec_name_list, ps_dict, binning_file, error_method="master", spectra=None, l_exact=None, l_band=None, l_toep=None, mbb_inv=None, compute_T_only=False, transfer_function=None, ): """Compute the covariance matrix of the power spectrum in the patch Parameters ---------- window: so_map the window function of the patch lmax: integer the maximum multipole to consider for the spectra computation spec_name_list: list the list of power spectra For example : [split0xsplit0,split0xsplit1,split1xsplit1] note that for computing the error on PS(split0xsplit1) we need PS(split0xsplit0), PS(split0xsplit1), PS(split1xsplit1) ps_dict: dict a dict containing all power spectra binning_file: text file a binning file with three columns bin low, bin high, bin mean note that either binning_file or bin_size should be provided error_method: string the method for the computation of error can be "master" or "knox" for now approx_coupling: dict mbb_inv: 2d array the inverse mode coupling matrix, not in use for 2dflat compute_T_only: boolean True to compute only T spectra transfer_function: str the path to the transfer function """ timer.start("Compute {} error...".format(error_method)) bin_lo, bin_hi, bin_c, bin_size = pspy_utils.read_binning_file( binning_file, lmax) fsky = enmap.area(window.data.shape, window.data.wcs) / 4.0 / np.pi fsky *= np.mean(window.data) cov_dict = {} if error_method == "knox": for name in spec_name_list: m1, m2 = name.split("x") cov_dict[name] = {} for spec in spectra: X, Y = spec prefac = 1 / ((2 * bin_c + 1) * fsky * bin_size) # fmt: off cov_dict[name][X + Y] = np.diag( prefac * (ps_dict["%sx%s" % (m1, m1)][X + X] * ps_dict["%sx%s" % (m2, m2)][Y + Y] + ps_dict["%sx%s" % (m1, m2)][X + Y]**2)) # fmt: on elif error_method == "master": if not compute_T_only: mbb_inv = mbb_inv["spin0xspin0"] coupling_dict = so_cov.cov_coupling_spin0(window, lmax, niter=0, l_band=l_band, l_toep=l_toep, l_exact=l_exact) coupling = so_cov.bin_mat(coupling_dict["TaTcTbTd"], binning_file, lmax) for name in spec_name_list: m1, m2 = name.split("x") cov_dict[name] = {} for spec in spectra: X, Y = spec cov_dict[name][X + Y] = so_cov.symmetrize( ps_dict["%sx%s" % (m1, m1)][X + X]) * so_cov.symmetrize( ps_dict["%sx%s" % (m2, m2)][Y + Y]) cov_dict[name][X + Y] += so_cov.symmetrize( ps_dict["%sx%s" % (m1, m2)][X + Y]**2) cov_dict[name][X + Y] *= coupling cov_dict[name][X + Y] = np.dot( np.dot(mbb_inv, cov_dict[name][X + Y]), mbb_inv.T) if transfer_function is not None: _, _, tf, _ = np.loadtxt(transfer_function, unpack=True) tf = tf[:len(bin_c)] cov_dict[name][X + Y] /= np.outer(np.sqrt(tf), np.sqrt(tf)) else: cov_dict = None timer.stop() return cov_dict