def to_pixel(self, Nside=None, Npix=None, dtype=None, out=None): """ :: >>> insh = harmonic_sphere_map(0, 0, 4) >>> insh.to_pixel(8) Pixel sphere map (ring-ordered, Nside=8, Npix=768) Convert a uniform map:: >>> shmap = harmonic_sphere_map([[23], [0, 0], [0, 0, 0]]) >>> pixmap = shmap.to_pixel(8); pixmap Pixel sphere map (ring-ordered, Nside=8, Npix=768) >>> np.allclose(pixmap, 23.0 / np.sqrt(4*np.pi)) True One can convert multiple maps at once:: >>> M = shmap >>> M = np.hstack((M[:,None], M[:,None], M[:,None], M[:,None])) >>> M = np.dstack((M, M)) >>> M = harmonic_sphere_map(M, 0, 2); M (4, 2)-stack of brief complex harmonic sphere maps with l=0..2 (6 coefficients) >>> x = M.to_pixel(4); x (4, 2)-stack of pixel sphere maps (ring-ordered, Nside=4, Npix=192) >>> np.allclose(x, 23.0 / np.sqrt(4*np.pi)) True """ self._check_not_pretending() if self.format is not COMPLEX_BRIEF: return self.to_complex().to_pixel(Nside, Npix, dtype, out) if Nside is None: if Npix is None: raise ValueError("Provide Nside or Npix") Nside = npix2nside(Npix) if Npix is None: Npix = nside2npix(Nside) if dtype is None: dtype = self.dtype dtype = to_real_dtype(dtype) # for now, only double... assert dtype == np.float64 size = self.shape[1:] if out is None: out = np.empty((Npix,) + size, dtype, order='F') # Todo: Optimize -- have lmin in complexpacked2complexmatrix if self.lmin == 0: source = self else: source = np.empty((l_to_lm(self.lmax + 1),) + size, complex_dtype, order='F') source[:l_to_lm(self.lmin)] = 0 source[l_to_lm(self.lmin):] = self for mapidx in np.ndindex(*size): idx = (slice(None),) + mapidx alm_matrix = mapdatautils.alm_complexpacked2complexmatrix(source[idx]) mapdatautils.alm2map(Nside, alm_matrix, out=out[idx]) return _PixelSphereMap(out, pixel_order='ring')
def rotate(self, psi, theta, phi): """ Returns a rotated copy of self. O(lmax^3). :: >>> M = harmonic_sphere_map([[1, 0], [1, 0, 0]], lmin=1) >>> R = M.rotate(0, np.pi, 0); R Brief complex harmonic sphere map with l=1..2 (5 coefficients) >>> np.round(R.to_array(), 4) array([-1.+0.j, -0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]) One can convert multiple maps at once:: TODO write tests """ from healpix import rotate_alm_d self._check_not_pretending() if psi == 0 and theta == 0 and phi == 0: return self.copy() if self.format is not COMPLEX_BRIEF: x = self.to_complex().rotate(psi, theta, phi) if self.format is REAL_FULL: return x.to_real() else: assert False size = self.shape[1:] # Todo: Optimize -- have lmin in complexpacked2complexmatrix out = np.empty((l_to_lm(self.lmax + 1),) + size, complex_dtype, order='F') out[:l_to_lm(self.lmin), ...] = 0 out[l_to_lm(self.lmin):, ...] = self alm_matrix = np.empty((1, self.lmax + 1, self.lmax + 1), complex_dtype, order='F') for mapidx in np.ndindex(*size): idx = (slice(None),) + mapidx mapdatautils.alm_complexpacked2complexmatrix(out[idx], alm_matrix[0,:,:]) rotate_alm_d(self.lmax, alm_matrix, psi, theta, phi) mapdatautils.alm_complexmatrix2complexpacked(alm_matrix[0,:,:], out[idx]) out = out[l_to_lm(self.lmin):, ...] return _HarmonicSphereMap(out, self.lmin, self.lmax, COMPLEX_BRIEF)
def simulate_harmonic_sphere_maps(lmin, lmax, size=None, state=np.random): """ Simulates standard normal maps in spherical harmonic space. INPUT: - ``n`` - The number of maps to simulate EXAMPLES:: >>> simulate_harmonic_sphere_maps(0, 3) Brief complex harmonic sphere map with l=0..3 (10 coefficients) >>> simulate_harmonic_sphere_maps(2, 3, size=10) (10,)-stack of brief complex harmonic sphere maps with l=2..3 (7 coefficients) """ if size is None: size = () if not isinstance(size, tuple): size = (size,) real_coefs = (lmax+1)**2 complex_coefs = l_to_lm(lmax+1) lmin_lm = l_to_lm(lmin) Zreal = state.standard_normal((real_coefs,) + size).astype(real_dtype) Zcomplex = np.empty((complex_coefs,) + size, complex_dtype) Zcomplex if len(size) > 1: raise NotImplementedError() # TODO: Have lmin in realpacked2complexpacked # For now, just slice away output for 0:lmin if size == (): mapdatautils.alm_realpacked2complexpacked(Zreal, out=Zcomplex) else: for i in range(size[0]): mapdatautils.alm_realpacked2complexpacked(Zreal[:,i], out=Zcomplex[:,i]) return _HarmonicSphereMap(Zcomplex[l_to_lm(lmin):, ...], lmin, lmax, COMPLEX_BRIEF)
def harmonic_sphere_map(data, lmin=0, lmax=None, is_complex=None, is_brief=None): """ Constructs a sphere map in harmonic space. EXAMPLES:: >>> M = harmonic_sphere_map([[0], [1, 3+1j], [1, 1, 1], [1, 1, 1, 1]]); M Brief complex harmonic sphere map with l=0..3 (10 coefficients) >>> M2 = harmonic_sphere_map([[1, 1, 1, 1]], lmin=3); M2 Brief complex harmonic sphere map with l=3..3 (4 coefficients) >>> harmonic_sphere_map([[0], [1 + 1j, 3+1j]]) Traceback (most recent call last): ... ValueError: Entries on m=0-positions must be real >>> harmonic_sphere_map(np.dstack((M[:,None,None], M[:,None,None]))) (1, 2)-stack of brief complex harmonic sphere maps with l=0..3 (10 coefficients) >>> M = harmonic_sphere_map(2, 0, 100); M Brief complex harmonic sphere map with l=0..100 (5151 coefficients) >>> np.sin(M) + 34 * M Brief complex harmonic sphere map with l=0..100 (5151 coefficients) Real coefficients are also supported:: >>> M = harmonic_sphere_map([[0], [-1, 1, 3], [-1, -2, 3, 4, 5]]); M Real harmonic sphere map with l=0..2 (9 coefficients) Scalar initialization:: >>> harmonic_sphere_map(10, 2, 4) Brief complex harmonic sphere map with l=2..4 (12 coefficients) """ if np.isscalar(data): if is_complex is None: is_complex = True if lmax is None: raise ValueError('Cannot infer lmax from data') data = (np.ones(l_to_lm(lmax + 1, is_complex) - l_to_lm(lmin, is_complex), dtype=complex_dtype if is_complex else real_dtype, order='F') * float(data)) elif isinstance(data, list): # Need at least two nesting levels of lists if (not isinstance(data[0], list) or isinstance(data[0][0], list)): raise ValueError("Please provide coefficients as [[a00], [a10, a11], ...]") if lmax is None: lmax = len(data) + lmin - 1 if is_complex is None: # Auto-detect is_complex from data if lmin == 0 and len(data) == 1: is_complex = True # only a00 given; assume is_complex elif lmin == 0: is_complex = (len(data[1]) == 2) else: is_complex = len(data[0]) == lmin + 1 num_coefs = l_to_lm(lmax + 1, is_complex) - l_to_lm(lmin, is_complex) buf = np.zeros(num_coefs, dtype=complex_dtype if is_complex else real_dtype, order='F') i = 0 for l, coefs_for_l in zip(range(lmin, lmax+1), data): n = l+1 if is_complex else 2*l + 1 if len(coefs_for_l) != n: raise ValueError("Wrong number of coefficients for l=%d" % l) if coefs_for_l[0].imag != 0: raise ValueError("Entries on m=0-positions must be real") buf[i:i+n] = coefs_for_l i += n data = buf else: if is_complex is None: is_complex = True data = np.asfortranarray(data, dtype=complex_dtype if is_complex else real_dtype) lmax_wanted = num_alm_to_lmax(l_to_lm(lmin, is_complex) + data.shape[0], is_complex) if lmax is not None and lmax != lmax_wanted: raise ValueError('lmax given does not match data lmax') if lmax is None: lmax = lmax_wanted if is_brief is None: is_brief = is_complex if is_complex: format = COMPLEX_BRIEF if is_brief else COMPLEX_FULL else: if is_brief: raise ValueError() format = REAL_FULL return _HarmonicSphereMap(data, lmin=lmin, lmax=lmax, format=format)
def to_harmonic(self, lmin, lmax, use_weights=True, weights_transform=None): """ :: >>> inpix = pixel_sphere_map(0, 4) >>> inpix.to_harmonic(0, 8) Brief complex harmonic sphere map with l=0..8 (45 coefficients) Convert a uniform map. First elements should be 12*sqrt(4 pi), the remaining elements 0:: >>> N = pixel_sphere_map(Nside=8, data=12) >>> x = N.to_harmonic(0, 16) >>> np.allclose(x[0], 12 * np.sqrt(4*np.pi)) True >>> np.allclose(x[1:], 0, atol=1e-1) True One can convert multiple maps at once: >>> N = np.hstack((N[:,None], N[:,None], N[:,None], N[:,None])) >>> N = np.dstack((N, N)) >>> N = pixel_sphere_map(data=N, Nside=8); N (4, 2)-stack of pixel sphere maps (ring-ordered, Nside=8, Npix=768) >>> x = N.to_harmonic(0, 16); x (4, 2)-stack of brief complex harmonic sphere maps with l=0..16 (153 coefficients) >>> np.allclose(x[0,:,:], 12 * np.sqrt(4*np.pi)) True >>> np.allclose(x[1:,:,:], 0, atol=.1) True """ if self.pixel_order == 'nested': return self.to_ring().to_harmonic(lmin, lmax) assert self.pixel_order == 'ring' self._check_not_pretending() dtype = to_complex_dtype(self.dtype) # for now, only double... assert dtype == np.complex128 size = self.shape[1:] numalm = l_to_lm(lmax + 1) alm_matrix_buf = np.empty((lmax + 1, lmax + 1), complex_dtype, order='F') alm = np.empty((numalm,) + size, complex_dtype, order='F') if use_weights: weight_ring_temperature = healpix_res.weight_ring(Nside=self.Nside)[0,:] if weights_transform is not None: weight_ring_temperature = weights_transform(weight_ring_temperature) else: weight_ring_temperature = np.ones(2 * self.Nside) for mapidx in np.ndindex(*size): idx = (slice(None),) + mapidx map = self[idx] mapdatautils.map2alm(lmax, map, weight_ring_temperature, out=alm_matrix_buf) mapdatautils.alm_complexmatrix2complexpacked(alm_matrix_buf, out=alm[idx]) # Trim away portion up to lmin alm = alm[l_to_lm(lmin):,...] return _HarmonicSphereMap(alm, lmin, lmax, COMPLEX_BRIEF)