def test_pospix(self): # Posmap separable and non-separable on CAR for res in [6,12,24]: shape,wcs = enmap.fullsky_geometry(res=np.deg2rad(res/60.),proj='car') posmap1 = enmap.posmap(shape,wcs) posmap2 = enmap.posmap(shape,wcs,separable=True) assert np.all(np.isclose(posmap1,posmap2)) # Pixmap plain pres = 0.5 shape,wcs = enmap.geometry(pos=(0,0),shape=(30,30),res=pres*u.degree,proj='plain') yp,xp = enmap.pixshapemap(shape,wcs) assert np.all(np.isclose(yp,pres*u.degree)) assert np.all(np.isclose(xp,pres*u.degree)) yp,xp = enmap.pixshape(shape,wcs) parea = enmap.pixsize(shape,wcs) assert np.isclose(parea,(pres*u.degree)**2) assert np.isclose(yp,pres*u.degree) assert np.isclose(xp,pres*u.degree) pmap = enmap.pixsizemap(shape,wcs) assert np.all(np.isclose(pmap,(pres*u.degree)**2)) # Pixmap CAR pres = 0.1 dec_cut = 89.5 # pixsizemap is not accurate near the poles currently shape,wcs = enmap.band_geometry(dec_cut=dec_cut*u.degree,res=pres*u.degree,proj='car') # Current slow and general but inaccurate near the poles implementation pmap = enmap.pixsizemap(shape,wcs) # Fast CAR-specific pixsizemap implementation dra, ddec = wcs.wcs.cdelt*u.degree dec = enmap.posmap([shape[-2],1],wcs)[0,:,0] area = np.abs(dra*(np.sin(np.minimum(np.pi/2.,dec+ddec/2))-np.sin(np.maximum(-np.pi/2.,dec-ddec/2)))) Nx = shape[-1] pmap2 = enmap.ndmap(area[...,None].repeat(Nx,axis=-1),wcs) assert np.all(np.isclose(pmap,pmap2))
def apod_C2(input_mask, radius): r""" Apodizes an input mask over a radius in degrees. A sharp mask will cause complicated mode coupling and ringing. One solution is to smooth out the sharp edges. This function applies the C2 apodisation as defined in 0903.2350_. .. _0903.2350: https://arxiv.org/abs/0903.2350 Parameters ---------- input_mask: enmap The input mask (must have all pixel values be non-negative). radius: float Apodization radius in degrees. Returns ------- result : enmap The apodized mask. """ if radius == 0: return input_mask else: dist = get_distance(input_mask) id = np.where(dist > radius) win = dist / radius - np.sin(2 * np.pi * dist / radius) / (2 * np.pi) win[id] = 1 return enmap.ndmap(win, input_mask.wcs)
def _enmapify(self, data): """Promote a numpy.ndarray to an enmap.ndmap by attaching wcs=self.geom[1]. In sensible cases (e.g. data is an ndarray or ndmap) this will not cause a copy of the underlying data array. """ return enmap.ndmap(data, wcs=self.geom[1])
def get_map(self,weights=None): if self.verbose: print("Calculating histogram...") if self.curved: return np.histogram(self.pixs,bins=self.shape,weights=weights,range=[0,self.shape],density=False)[0].astype(np.float32) else: Ny,Nx = self.shape[-2:] return enmap.ndmap(np.histogram2d(self.pixs[0,:],self.pixs[1,:], bins=self.shape,weights=weights, range=[[0,Ny],[0,Nx]],density=False)[0],self.wcs)
def filter_riseset(imap, ivar, riseset, filter, tol=1e-4, ref=0.9): """Filter enmap imap with the given 2d fourier filter while weighting spatially with ivar and allowing for rise vs set-dependent pickup. riseset should be a map with values between -1 and 1 that determines the balance between rising and setting scans, with 0 meaning equal weight from both. Overall this is only a marginal improvement over filter_weighted depsite being quite a bit heaver, and it only helps a bit for the pa7 residual stripe issue it was invented to deal with, so it probably isn't worth using. """ # We model the map as m = Pa+n, where a is [2] is the rising and setting pickup in # a single pixel, and P is the map's response to this pickup, which is # P = [x,1-x]*filter, where x=(1-riseset)/2. Given this we can solve for a as: # a = (P'N"P)"P'N"m, where N" is ivar. Written out this becomes, for a single pixel. # rhs = ifft(filter*fft([x,1-x]*ivar*imap)) # div = ifft(filter*fft([x,1-x]*ivar*[x,1-x]*ifft(filter) # Hm.... The problem here is that we're assuming that there's nothing in the other pixels. # That's not what we did in filter_weighted. Let's just do something simple for now. x = (1 - riseset) / 2 x1x = np.array([x, 1 - x]) del x # Broadcast to imap shape x1x = x1x[(slice(None), ) + (None, ) * (imap.ndim - 2)] print(imap.shape, x1x.shape) filter = 1 - filter rhs = enmap.ifft(filter * enmap.fft(x1x * ivar * imap)).real div = enmap.ifft(filter * enmap.fft(x1x[:, None] * x1x[None, :] * ivar)).real del filter # Avoid division by very low values ref = np.percentile(ivar[::10, ::10], ref * 100) * tol for i in range(2): div[i, i] = np.maximum(div[i, i], ref) # Solve the system rhs = np.moveaxis(rhs, 0, -1) div = np.moveaxis(div, (0, 1), (-2, -1)) omap = np.linalg.solve(div, rhs) del rhs, div omap = np.sum(x1x * np.moveaxis(omap, -1, 0), 0) del x1x omap = enmap.ndmap(omap, imap.wcs) omap *= -1 omap += imap omap *= imap != 0 return omap
def getActpolCmbFgSim(beamfileDict, shape, wcs, iterationNum, cmbDir, freqs, psa, cmbSet = 0, \ doBeam = True, applyWindow = True, verbose = True, cmbMaptype = 'LensedCMB', foregroundSeed = 0, simType = 'cmb', foregroundPowerFile = None, applyModulation = True): nTQUs = len('TQU') firstTime = True output = enmap.empty(( len(freqs), nTQUs, ) + shape[-2:], wcs) if simType == 'cmb': filename = cmbDir + "/fullsky%s_alm_set%02d_%05d.fits" % ( cmbMaptype, cmbSet, iterationNum) if verbose: print('getActpolCmbFgSim(): loading CMB a_lms from %s' % filename) import healpy almTebFullskyOnecopy = np.complex128( healpy.fitsfunc.read_alm(filename, hdu=(1, 2, 3))) #Now tile the same for all the frequencies requested (i.e. CMB is same at all frequencies). #The beam convolution happens below. almTebFullsky = np.tile(almTebFullskyOnecopy, (len(freqs), 1, 1)) if verbose: print('getActpolCmbFgSim(): done') elif simType == 'foregrounds': outputFreqs = ['f090', 'f150'] foregroundPowers \ = powspec.read_spectrum(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../data/', foregroundPowerFile), ncol = 3, expand = 'row') if verbose: print('getActpolCmbFgSim(): getting foreground a_lms') almTFullsky90and150 = curvedsky.rand_alm(foregroundPowers, seed=foregroundSeed) almTebFullsky = np.zeros(( len(freqs), nTQUs, ) + (len(almTFullsky90and150[-1]), ), dtype=np.complex128) for fi, freq in enumerate(freqs): if freq in outputFreqs: almTebFullsky[fi, 'TQU'.index('T'), :] \ = almTFullsky90and150[outputFreqs.index(freq), :] #Convolve with beam on full sky for fi, freq in enumerate(freqs): if doBeam: beamFile = beamfileDict[psa + '_' + freq] if verbose: print('getActpolCmbFgSim(): applying beam from %s' % beamFile) beamData = (np.loadtxt(beamFile))[:, 1] else: if verbose: print('getActpolCmbFgSim(): not convolving with beam') beamData = np.repeat(1., almTebFullsky.shape[-1]) import healpy #couldn't quickly figure out how to vectorize this so loop from 0 to 2. for tqui in range(nTQUs): almTebFullsky[fi, tqui] = healpy.sphtfunc.almxfl( almTebFullsky[fi, tqui].copy(), beamData) #These lines stolen from curvedsky.rand_map #doing all freqs at once gives error: #sharp.pyx in sharp.execute_dp (cython/sharp.c:12118)() #ValueError: ndarray is not C-contiguous #so loop over all freqs once for now. curvedsky.alm2map(almTebFullsky, output, spin=[0, 2], verbose=True) # outputThisfreq = enmap.empty(( nTQUs,)+shape[-2:], wcs) # curvedsky.alm2map(almTebFullsky[fi,:,:], outputThisfreq, spin = [0,2], verbose = True) # output[fi,...] = outputThisfreq # curvedsky.alm2map(almTebFullsky[fi,:,:], output[fi,:,:,:], spin = [0,2], verbose = True) if applyModulation: from pixell import aberration for fi, freq in enumerate(freqs): print('applying modulation for frequency %s' % freq) output, A = aberration.boost_map(output, aberration.dir_equ, aberration.beta, return_modulation=True, aberrate=False, freq=freqStrToValGhz[freq] * 1e9) if applyWindow: from pixell import fft #The axes along which to FFT axes = [-2, -1] if verbose: print('getActpolCmbFgSim(): applying pixel window function') nfreq = len(freqs) for idx in range(nfreq): fd = fft.fft(output[idx], axes=axes) wy, wx = enmap.calc_window(fd.shape) twoDWindow = wy[:, None]**1 * wx[None, :]**1 #Careful, this is quietly multiplying an array with shape [N_freq, N_TQU, N_y, N_x] with one of shape [N_y, N_x] fd *= twoDWindow output[idx] = (fft.ifft(fd, axes=axes, normalize=True)).real del fd if verbose: print('getActpolCmbFgSim(): done') return enmap.ndmap(output, wcs)
def read_data(fnames, sel=None, pixbox=None, box=None, geometry=None, comp=0, split=0, unit="flux", dtype=np.float32, beam_rmax=5 * utils.degree, beam_res=2 * utils.arcsec, deconv_pixwin=True, apod=15 * utils.arcmin, mask=None, ivscale=[1, 0.5, 0.5]): """Read multi-frequency data for a single split of a single component, preparing it for analysis.""" # Read in our data files and harmonize br = np.arange(0, beam_rmax, beam_res) data = bunch.Bunch(maps=[], ivars=[], beams=[], freqs=[], l=None, bls=[], names=[], beam_profiles=[]) for ifile in fnames: d = mapdata.read(ifile, sel=sel, pixbox=pixbox, box=box, geometry=geometry) # The 0 here is just selecting the first split. That is, we don't support splits data.maps.append(d.maps[split].astype(dtype)[comp]) data.ivars.append(d.ivars[split].astype(dtype) * ivscale[comp]) data.freqs.append(d.freq) if data.l is None: data.l = d.maps[0].modlmap() data.beams.append( enmap.ndmap( np.interp(data.l, np.arange(len(d.beam)), d.beam / np.max(d.beam)), d.maps[0].wcs).astype(dtype)) data.names.append(".".join(os.path.basename(ifile).split(".")[:-1])) data.bls.append(d.beam) data.beam_profiles.append( np.array([br, curvedsky.harm2profile(d.beam, br)]).astype(dtype)) data.maps = enmap.enmap(data.maps) data.ivars = enmap.enmap(data.ivars) data.beams = enmap.enmap(data.beams) data.freqs = np.array(data.freqs) if unit == "uK": data.fconvs = np.full(len(data.freqs), 1.0, dtype) elif unit == "flux": data.fconvs = (utils.dplanck(data.freqs * 1e9, utils.T_cmb) / 1e3).astype(dtype) # uK -> mJy/sr else: raise ValueError("Unrecognized unit '%s'" % str(unit)) data.n = len(data.freqs) # Apply the unit data.maps *= data.fconvs[:, None, None] data.ivars /= data.fconvs[:, None, None]**2 if mask is not None: mask_map = 1 - enmap.read_map(mask, sel=sel, pixbox=pixbox, box=box) data.ivars *= mask_map del mask_map # Should generalize this to handle internal map edges and frequency differences mask = enmap.shrink_mask(enmap.grow_mask(data.ivars > 0, 1 * utils.arcmin), 1 * utils.arcmin) apod_map = enmap.apod_mask(mask, apod) data.apod = apod_map data.fapod = np.mean(apod_map**2) data.maps *= apod_map data.ivars *= apod_map**2 # Get the pixel window and optionall deconvolve it data.wy, data.wx = [ w.astype(dtype) for w in enmap.calc_window(data.maps.shape) ] if deconv_pixwin: data.maps = enmap.ifft( enmap.fft(data.maps) / data.wy[:, None] / data.wx[None, :]).real return data
def unzip(self, x): return enmap.ndmap(x.reshape(self.shape), self.wcs)