def rand_map(shape, wcs, ps, lmax=None, dtype=np.float64, seed=None, oversample=2.0, spin=2, method="auto"): """Generates a CMB realization with the given power spectrum for an enmap with the specified shape and WCS. This is identical to enlib.rand_map, except that it takes into account the curvature of the full sky. This makes it much slower and more memory-intensive. The map should not cross the poles.""" # Ensure everything has the right dimensions and restrict to relevant dimensions ps = utils.atleast_3d(ps) assert ps.shape[0] == ps.shape[1], "ps must be [ncomp,ncomp,nl] or [nl]" assert len(shape) == 2 or len( shape) == 3, "shape must be (ncomp,ny,nx) or (ny,nx)" ncomp = 1 if len(shape) == 2 else shape[-3] ps = ps[:ncomp, :ncomp] ctype = np.result_type(dtype, 0j) alm = rand_alm(ps, lmax=lmax, seed=seed, dtype=ctype) map = enmap.empty((ncomp, ) + shape[-2:], wcs, dtype=dtype) alm2map(alm, map, spin=spin, oversample=oversample, method=method) if len(shape) == 2: map = map[0] return map
def make_projectable_map_cyl(map, verbose=False): """Given an enmap in a cylindrical projection, return a map with the same pixelization, but extended to cover a whole band in phi around the sky. Also returns the slice required to recover the input map from the output map.""" # First check if we need flipping. Sharp wants theta,phi increasing, # which means dec decreasing and ra increasing. flipx = map.wcs.wcs.cdelt[0] < 0 flipy = map.wcs.wcs.cdelt[1] > 0 if flipx: map = map[..., :, ::-1] if flipy: map = map[..., ::-1, :] # Then check if the map satisfies the lat-ring requirements ny, nx = map.shape[-2:] vy, vx = enmap.pix2sky(map.shape, map.wcs, [np.arange(ny), np.zeros(ny)]) hy, hx = enmap.pix2sky(map.shape, map.wcs, [np.zeros(nx), np.arange(nx)]) dx = hx[1:] - hx[:-1] dx = dx[np.isfinite(dx)] # Handle overextended coordinates if not np.allclose(dx, dx[0]): raise ShapeError("Map must have constant phi spacing") nphi = utils.nint(2 * np.pi / dx[0]) if not np.allclose(2 * np.pi / nphi, dx[0]): raise ShapeError("Pixels must evenly circumference") if not np.allclose(vx, vx[0]): raise ShapeError( "Different phi0 per row indicates non-cylindrical enmap") phi0 = vx[0] # Make a map with the same geometry covering a whole band around the sky # We can do this simply by extending it in the positive pixel dimension. oshape = map.shape[:-1] + (nphi, ) owcs = map.wcs # Our input map could in theory cover multiple copies of the sky, which # would require us to copy out multiple slices. nslice = (nx + nphi - 1) // nphi islice, oslice = [], [] def negnone(x): return x if x >= 0 else None for i in range(nslice): # i1:i2 is the range of pixels in the original map to use i1, i2 = i * nphi, min((i + 1) * nphi, nx) islice.append((Ellipsis, slice(i1, i2))) # yslice and xslice give the range of pixels in our temporary map to use. # This is 0:(i2-i1) if we're not flipping, but if we flip we count from # the opposite direction: nx-1:nx-1-(i2-i1):-1 yslice = slice(-1, None, -1) if flipy else slice(None) xslice = slice(nx - 1, negnone(nx - 1 - (i2 - i1)), -1) if flipx else slice(0, i2 - i1) oslice.append((Ellipsis, yslice, xslice)) if verbose: print "Allocating shape %s dtype %s intermediate map" % ( str(oshape), np.dtype(map.dtype).char) return enmap.empty(oshape, owcs, dtype=map.dtype), islice, oslice
def __init__(self, geometry, tiles=None, copy=True): try: self.geometry = geometry.geometry self.tiles = [t.copy() for t in geometry.tiles] except AttributeError: self.geometry = geometry if tiles is not None: if copy: tiles = copy = deepcopy(tiles) self.tiles = tiles else: self.tiles = [ enmap.empty(ts, tw, dtype=geometry.dtype) for ts, tw in geometry.loc_geometry ]
def displace_map(imap, pix, order=3, mode="spline", border="cyclic", trans=False, deriv=False): """Displace map m[{pre},ny,nx] by pix[2,ny,nx], where pix indicates the location in the input map each output pixel should get its value from (float). The output is [{pre},ny,nx].""" iwork = np.empty(imap.shape[-2:] + imap.shape[:-2], imap.dtype) if not deriv: out = imap.copy() else: out = enmap.empty((2, ) + imap.shape, imap.wcs, imap.dtype) # Why do we have to manually allocate outputs and juggle whcih is copied over here? # Because it is in general not possible to infer from odata what shape idata should have. # So the map_coordinates can't allocate the output array automatically in the transposed # case. But in this function we know that they will have the same shape, so we can. if not trans: iwork[:] = utils.moveaxes(imap, (-2, -1), (0, 1)) owork = interpol.map_coordinates(iwork, pix, order=order, mode=mode, border=border, trans=trans, deriv=deriv) out[:] = utils.moveaxes(owork, (0, 1), (-2, -1)) else: if not deriv: owork = iwork.copy() else: owork = np.empty(imap.shape[-2:] + (2, ) + imap.shape[:-2], imap.dtype) owork[:] = utils.moveaxes(imap, (-2, -1), (0, 1)) interpol.map_coordinates(iwork, pix, owork, order=order, mode=mode, border=border, trans=trans, deriv=deriv) out[:] = utils.moveaxes(iwork, (0, 1), (-2, -1)) return out
def rand_map(shape, wcs, ps, lmax=None, dtype=np.float64, seed=None, oversample=2.0, spin=2, method="auto", direct=False, verbose=False): """Generates a CMB realization with the given power spectrum for an enmap with the specified shape and WCS. This is identical to enlib.rand_map, except that it takes into account the curvature of the full sky. This makes it much slower and more memory-intensive. The map should not cross the poles.""" # Ensure everything has the right dimensions and restrict to relevant dimensions ps = utils.atleast_3d(ps) if not ps.shape[0] == ps.shape[1]: raise ShapeError("ps must be [ncomp,ncomp,nl] or [nl]") if not (len(shape) == 2 or len(shape) == 3): raise ShapeError("shape must be (ncomp,ny,nx) or (ny,nx)") ncomp = 1 if len(shape) == 2 else shape[-3] ps = ps[:ncomp, :ncomp] ctype = np.result_type(dtype, 0j) if verbose: print "Generating alms with seed %s up to lmax=%d dtype %s" % ( str(seed), lmax, np.dtype(ctype).char) alm = rand_alm_healpy(ps, lmax=lmax, seed=seed, dtype=ctype) if verbose: print "Allocating output map shape %s dtype %s" % (str( (ncomp, ) + shape[-2:]), np.dtype(dtype).char) map = enmap.empty((ncomp, ) + shape[-2:], wcs, dtype=dtype) alm2map(alm, map, spin=spin, oversample=oversample, method=method, direct=direct, verbose=verbose) if len(shape) == 2: map = map[0] return map
def rand_map(shape, wcs, ps_lensinput, lmax=None, maplmax=None, dtype=np.float64, seed=None, oversample=2.0, spin=2, output="l", geodesic=True, verbose=False, delta_theta=None): import curvedsky, sharp ctype = np.result_type(dtype, 0j) # Restrict to target number of components oshape = shape[-3:] if len(oshape) == 2: shape = (1, ) + tuple(shape) # First draw a random lensing field, and use it to compute the undeflected positions if verbose: print("Generating alms") alm, ainfo = curvedsky.rand_alm(ps_lensinput, lmax=lmax, seed=seed, dtype=ctype, return_ainfo=True) phi_alm, cmb_alm = alm[0], alm[1:1 + shape[-3]] # Truncate alm if we want a smoother map. In taylens, it was necessary to truncate # to a lower lmax for the map than for phi, to avoid aliasing. The appropriate lmax # for the cmb was the one that fits the resolution. FIXME: Can't slice alm this way. #if maplmax: cmb_alm = cmb_alm[:,:maplmax] del alm if delta_theta is None: bsize = shape[-2] else: bsize = utils.nint(abs(delta_theta / utils.degree / wcs.wcs.cdelt[1])) # Adjust bsize so we don't get any tiny blocks at the end nblock = shape[-2] // bsize bsize = int(shape[-2] / (nblock + 0.5)) # Allocate output maps if "p" in output: phi_map = enmap.empty(shape[-2:], wcs, dtype=dtype) if "k" in output: kappa_map = enmap.empty(shape[-2:], wcs, dtype=dtype) l = np.arange(ainfo.lmax + 1.0) kappa_alm = ainfo.lmul(phi_alm, l * (l + 1) / 2) for i1 in range(0, shape[-2], bsize): curvedsky.alm2map(kappa_alm, kappa_map[..., i1:i1 + bize, :]) del kappa_alm if "a" in output: grad_map = enmap.empty((2, ) + shape[-2:], wcs, dtype=dtype) if "u" in output: cmb_raw = enmap.empty(shape, wcs, dtype=dtype) if "l" in output: cmb_obs = enmap.empty(shape, wcs, dtype=dtype) # Then loop over dec bands for i1 in range(0, shape[-2], bsize): i2 = min(i1 + bsize, shape[-2]) lshape, lwcs = enmap.slice_geometry(shape, wcs, (slice(i1, i2), slice(None))) if "p" in output: if verbose: print("Computing phi map") curvedsky.alm2map(phi_alm, phi_map[..., i1:i2, :]) if verbose: print("Computing grad map") if "a" in output: grad = grad_map[..., i1:i2, :] else: grad = enmap.zeros((2, ) + lshape[-2:], lwcs, dtype=dtype) curvedsky.alm2map(phi_alm, grad, deriv=True) if "l" not in output: continue if verbose: print("Computing observed coordinates") obs_pos = enmap.posmap(lshape, lwcs) if verbose: print("Computing alpha map") raw_pos = enmap.samewcs( offset_by_grad(obs_pos, grad, pol=shape[-3] > 1, geodesic=geodesic), obs_pos) del obs_pos, grad if "u" in output: if verbose: print("Computing unlensed map") curvedsky.alm2map(cmb_alm, cmb_raw[..., i1:i2, :], spin=spin) if verbose: print("Computing lensed map") cmb_obs[..., i1:i2, :] = curvedsky.alm2map_pos(cmb_alm, raw_pos[:2], oversample=oversample, spin=spin) if raw_pos.shape[0] > 2 and np.any(raw_pos[2]): if verbose: print("Rotating polarization") cmb_obs[..., i1:i2, :] = enmap.rotate_pol(cmb_obs[..., i1:i2, :], raw_pos[2]) del raw_pos del cmb_alm, phi_alm # Output in same order as specified in output argument res = [] for c in output: if c == "l": res.append(cmb_obs.reshape(oshape)) elif c == "u": res.append(cmb_raw.reshape(oshape)) elif c == "p": res.append(phi_map) elif c == "k": res.append(kappa_map) elif c == "a": res.append(grad_map) return tuple(res)