def smoothalm(alms, fwhm=0.0, sigma=None, invert=False, pol=True, mmax=None, verbose=False, inplace=True): """Smooth alm with a Gaussian symmetric beam function. Parameters ---------- alms : array or sequence of 3 arrays Either an array representing one alm, or a sequence of arrays. See *pol* parameter. fwhm : float, optional The full width half max parameter of the Gaussian. Default:0.0 [in radians] sigma : float, optional The sigma of the Gaussian. Override fwhm. [in radians] invert : bool, optional If True, alms are divided by Gaussian beam function (un-smooth). Otherwise, alms are multiplied by Gaussian beam function (smooth). Default: False. pol : bool, optional If True, assumes input alms are TEB. Output will be TQU maps. (input must be 1 or 3 alms) If False, apply spin 0 harmonic transform to each alm. (input can be any number of alms) If there is only one input alm, it has no effect. Default: True. mmax : None or int, optional The maximum m for alm. Default: mmax=lmax inplace : bool, optional If True, the alm's are modified inplace if they are contiguous arrays of type complex128. Otherwise, a copy of alm is made. Default: True. verbose : bool, optional If True prints diagnostic information. Default: False Returns ------- alms : array or sequence of 3 arrays The smoothed alm. If alm[i] is a contiguous array of type complex128, and *inplace* is True the smoothing is applied inplace. Otherwise, a copy is made. """ if sigma is None: sigma = fwhm / (2.0 * np.sqrt(2.0 * np.log(2.0))) if verbose: print "Sigma is %f arcmin (%f rad) " % (sigma * 60 * 180 / pi, sigma) print "-> fwhm is %f arcmin" % (sigma * 60 * 180 / pi * (2.0 * np.sqrt(2.0 * np.log(2.0)))) # Check alms if not cb.is_seq(alms): raise ValueError("alm must be a sequence") if sigma == 0: # nothing to be done return alms lonely = False if not cb.is_seq_of_seq(alms): alms = [alms] lonely = True # we have 3 alms -> apply smoothing to each map. # polarization has different B_l from temperature # exp{-[ell(ell+1) - s**2] * sigma**2/2} # with s the spin of spherical harmonics # s = 2 for pol, s=0 for temperature retalm = [] for ialm, alm in enumerate(alms): lmax = Alm.getlmax(len(alm), mmax) if lmax < 0: raise TypeError("Wrong alm size for the given " "mmax (len(alms[%d]) = %d)." % (ialm, len(alm))) ell = np.arange(lmax + 1.0) s = 2 if ialm >= 1 and pol else 0 fact = np.exp(-0.5 * (ell * (ell + 1) - s ** 2) * sigma ** 2) res = almxfl(alm, fact, mmax=mmax, inplace=inplace) retalm.append(res) # Test what to return (inplace/not inplace...) # Case 1: 1d input, return 1d output if lonely: return retalm[0] # case 2: 2d input, check if in-place smoothing for all alm's for i in xrange(len(alms)): samearray = alms[i] is retalm[i] if not samearray: # Case 2a: # at least one of the alm could not be smoothed in place: # return the list of alm return retalm # Case 2b: # all smoothing have been performed in place: # return the input alms return alms
def smoothing( maps, fwhm=0.0, sigma=None, invert=False, pol=True, iter=3, lmax=None, mmax=None, use_weights=False, regression=True, datapath=None, ): """Smooth a map with a Gaussian symmetric beam. Parameters ---------- maps : array or sequence of 3 arrays Either an array representing one map, or a sequence of 3 arrays representing 3 maps, accepts masked arrays fwhm : float, optional The full width half max parameter of the Gaussian [in radians]. Default:0.0 sigma : float, optional The sigma of the Gaussian [in radians]. Override fwhm. invert : bool, optional If True, alms are divided by Gaussian beam function (un-smooth). Otherwise, alms are multiplied by Gaussian beam function (smooth). Default: False. pol : bool, optional If True, assumes input maps are TQU. Output will be TQU maps. (input must be 1 or 3 alms) If False, each map is assumed to be a spin 0 map and is treated independently (input can be any number of alms). If there is only one input map, it has no effect. Default: True. iter : int, scalar, optional Number of iteration (default: 3) lmax : int, scalar, optional Maximum l of the power spectrum. Default: 3*nside-1 mmax : int, scalar, optional Maximum m of the alm. Default: lmax use_weights: bool, scalar, optional If True, use the ring weighting. Default: False. regression: bool, scalar, optional If True, subtract map average before computing alm. Default: True. datapath : None or str, optional If given, the directory where to find the weights data. Returns ------- maps : array or list of 3 arrays The smoothed map(s) """ if not cb.is_seq(maps): raise TypeError("maps must be a sequence") # save the masks of inputs masks = pixelfunc.mask_bad(maps) if cb.is_seq_of_seq(maps): nside = pixelfunc.npix2nside(len(maps[0])) n_maps = len(maps) else: nside = pixelfunc.npix2nside(len(maps)) n_maps = 0 if pol or n_maps in (0, 1): # Treat the maps together (1 or 3 maps) alms = map2alm( maps, lmax=lmax, mmax=mmax, iter=iter, pol=pol, use_weights=use_weights, regression=regression, datapath=datapath, ) smoothalm(alms, fwhm=fwhm, sigma=sigma, invert=invert, inplace=True) output_map = alm2map(alms, nside, pixwin=False) else: # Treat each map independently (any number) output_map = [] for m, mask in zip(maps, masks): alm = map2alm(maps, iter=iter, pol=pol, use_weights=use_weights, regression=regression, datapath=datapath) smoothalm(alm, fwhm=fwhm, sigma=sigma, invert=invert, inplace=True) output_map.append(alm2map(alm, nside, pixwin=False)) if pixelfunc.maptype(output_map) == 0: output_map[masks.flatten()] = UNSEEN else: for m, mask in zip(output_map, masks): m[mask] = UNSEEN return output_map
def alm2map( alms, nside, lmax=None, mmax=None, pixwin=False, fwhm=0.0, sigma=None, invert=False, pol=True, inplace=False ): """Computes an Healpix map given the alm. The alm are given as a complex array. You can specify lmax and mmax, or they will be computed from array size (assuming lmax==mmax). Parameters ---------- alms : complex, array or sequence of arrays A complex array or a sequence of complex arrays. Each array must have a size of the form: mmax * (2 * lmax + 1 - mmax) / 2 + lmax + 1 nside : int, scalar The nside of the output map. lmax : None or int, scalar, optional Explicitly define lmax (needed if mmax!=lmax) mmax : None or int, scalar, optional Explicitly define mmax (needed if mmax!=lmax) pixwin : bool, optional Smooth the alm using the pixel window functions. Default: False. fwhm : float, scalar, optional The fwhm of the Gaussian used to smooth the map (applied on alm) [in radians] sigma : float, scalar, optional The sigma of the Gaussian used to smooth the map (applied on alm) [in radians] invert : bool, optional If True, alms are divided by Gaussian beam function (un-smooth). Otherwise, alms are multiplied by Gaussian beam function (smooth). Default: False. pol : bool, optional If True, assumes input alms are TEB. Output will be TQU maps. (input must be 1 or 3 alms) If False, apply spin 0 harmonic transform to each alm. (input can be any number of alms) If there is only one input alm, it has no effect. Default: True. inplace : bool, optional If True, input alms may be modified by pixel window function and beam smoothing (if alm(s) are complex128 contiguous arrays). Otherwise, input alms are not modified. A copy is made if needed to apply beam smoothing or pixel window. Returns ------- maps : array or list of arrays An Healpix map in RING scheme at nside or a list of T,Q,U maps (if polarized input) """ if not cb.is_seq(alms): raise TypeError("alms must be a sequence") alms = smoothalm(alms, fwhm=fwhm, sigma=sigma, invert=invert, pol=pol, inplace=inplace) if not cb.is_seq_of_seq(alms): alms = [alms] lonely = True else: lonely = False if pixwin: pw = globals()["pixwin"](nside, True) alms_new = [] for ialm, alm in enumerate(alms): pixelwindow = pw[1] if ialm >= 1 and pol else pw[0] alms_new.append(almxfl(alm, pixelwindow, inplace=inplace)) else: alms_new = alms if lmax is None: lmax = -1 if mmax is None: mmax = -1 if pol: output = sphtlib._alm2map(alms_new[0] if lonely else alms_new, nside, lmax=lmax, mmax=mmax) if lonely: output = [output] else: output = [sphtlib._alm2map(alm, nside, lmax=lmax, mmax=mmax) for alm in alms_new] if lonely: return output[0] else: return output
def synalm(cls, lmax=None, mmax=None, new=False): """Generate a set of alm given cl. The cl are given as a float array. Corresponding alm are generated. If lmax is None, it is assumed lmax=cl.size-1 If mmax is None, it is assumed mmax=lmax. Parameters ---------- cls : float, array or tuple of arrays Either one cl (1D array) or a tuple of either 4 cl or of n*(n+1)/2 cl. Some of the cl may be None, implying no cross-correlation. See *new* parameter. lmax : int, scalar, optional The lmax (if None or <0, the largest size-1 of cls) mmax : int, scalar, optional The mmax (if None or <0, =lmax) new : bool, optional If True, use the new ordering of cl's, ie by diagonal (e.g. TT, EE, BB, TE, EB, TB or TT, EE, BB, TE if 4 cl as input). If False, use the old ordering, ie by row (e.g. TT, TE, TB, EE, EB, BB or TT, TE, EE, BB if 4 cl as input). Returns ------- alms : array or list of arrays the generated alm if one spectrum is given, or a list of n alms (with n(n+1)/2 the number of input cl, or n=3 if there are 4 input cl). Notes ----- The order of the spectra will change in a future release. The new= parameter help to make the transition smoother. You can start using the new order by setting new=True. In the next version of healpy, the default will be new=True. This change is done for consistency between the different tools (alm2cl, synfast, anafast). In the new order, the spectra are ordered by diagonal of the correlation matrix. Eg, if fields are T, E, B, the spectra are TT, EE, BB, TE, EB, TB with new=True, and TT, TE, TB, EE, EB, BB if new=False. """ if not new: warnings.warn( "The order of the input cl's will change in a future " "release.\n" "Use new=True keyword to start using the new order.\n" "See documentation of healpy.synalm.", category=FutureChangeWarning, ) if not cb.is_seq(cls): raise TypeError("cls must be an array or a sequence of arrays") if not cb.is_seq_of_seq(cls): # Only one spectrum if lmax is None or lmax < 0: lmax = cls.size - 1 if mmax is None or mmax < 0: mmax = lmax cls_list = [np.asarray(cls, dtype=np.float64)] szalm = Alm.getsize(lmax, mmax) alm = np.zeros(szalm, "D") alm.real = np.random.standard_normal(szalm) alm.imag = np.random.standard_normal(szalm) alms_list = [alm] sphtlib._synalm(cls_list, alms_list, lmax, mmax) return alm # From here, we interpret cls as a list of spectra cls_list = list(cls) maxsize = max([len(c) for c in cls]) if lmax is None or lmax < 0: lmax = maxsize - 1 if mmax is None or mmax < 0: mmax = lmax Nspec = sphtlib._getn(len(cls_list)) if Nspec <= 0: if len(cls_list) == 4: if new: ## new input order: TT EE BB TE -> TT EE BB TE 0 0 cls_list = [cls[0], cls[1], cls[2], cls[3], None, None] else: ## old input order: TT TE EE BB -> TT TE 0 EE 0 BB cls_list = [cls[0], cls[1], None, cls[2], None, cls[3]] Nspec = 3 else: raise TypeError( "The sequence of arrays must have either 4 elements " "or n(n+1)/2 elements (some may be None)" ) szalm = Alm.getsize(lmax, mmax) alms_list = [] for i in xrange(Nspec): alm = np.zeros(szalm, "D") alm.real = np.random.standard_normal(szalm) alm.imag = np.random.standard_normal(szalm) alms_list.append(alm) if new: # new input order: input given by diagonal, should be given by row cls_list = new_to_old_spectra_order(cls_list) # ensure cls are float64 cls_list = [(np.asarray(cl, dtype=np.float64) if cl is not None else None) for cl in cls_list] sphtlib._synalm(cls_list, alms_list, lmax, mmax) return alms_list
def test_is_seq(): import numpy as np from healpy.cookbook import is_seq assert not is_seq(None) assert not is_seq(1) assert not is_seq(1.) assert not is_seq(np.array(1)) assert is_seq((1, 2, 3)) assert is_seq([1, 2, 3]) assert is_seq(np.array([1, 2, 3])) assert is_seq(np.array([[1], [2], [3]])) assert is_seq(()) assert is_seq([]) assert is_seq(np.array([]))
def smoothing(maps, fwhm = 0.0, sigma = None, invert = False, pol = True, iter = 3, lmax = None, mmax = None, use_weights = False, regression = True, datapath = None): """Smooth a map with a Gaussian symmetric beam. Parameters ---------- maps : array or sequence of 3 arrays Either an array representing one map, or a sequence of 3 arrays representing 3 maps fwhm : float, optional The full width half max parameter of the Gaussian. Default:0.0 sigma : float, optional The sigma of the Gaussian. Override fwhm. invert : bool, optional If True, alms are divided by Gaussian beam function (un-smooth). Otherwise, alms are multiplied by Gaussian beam function (smooth). Default: False. pol : bool, optional If True, assumes input maps are TQU. Output will be TQU maps. (input must be 1 or 3 alms) If False, each map is assumed to be a spin 0 map and is treated independently (input can be any number of alms). If there is only one input map, it has no effect. Default: True. iter : int, scalar, optional Number of iteration (default: 3) lmax : int, scalar, optional Maximum l of the power spectrum. Default: 3*nside-1 mmax : int, scalar, optional Maximum m of the alm. Default: lmax use_weights: bool, scalar, optional If True, use the ring weighting. Default: False. regression: bool, scalar, optional If True, subtract map average before computing alm. Default: True. datapath : None or str, optional If given, the directory where to find the weights data. Returns ------- maps : array or list of 3 arrays The smoothed map(s) """ if not cb.is_seq(maps): raise TypeError("maps must be a sequence") if cb.is_seq_of_seq(maps): nside = pixelfunc.npix2nside(len(maps[0])) n_maps = len(maps) else: nside = pixelfunc.npix2nside(len(maps)) n_maps = 0 if pol or n_maps in (0, 1): # Treat the maps together (1 or 3 maps) alms = map2alm(maps, lmax = lmax, mmax = mmax, iter = iter, pol = pol, use_weights = use_weights, regression = regression, datapath = datapath) smoothalm(alms, fwhm = fwhm, sigma = sigma, invert = invert, inplace = True) return alm2map(alms, nside, pixwin = False) else: # Treat each map independently (any number) retmaps = [] for m in maps: alm = map2alm(maps, iter = iter, pol = pol, use_weights = use_weights, regression = regression, datapath = datapath) smoothalm(alm, fwhm = fwhm, sigma = sigma, invert = invert, inplace = True) retmaps.append(alm2map(alm, nside, pixwin = False)) return retmaps
def smoothalm(alms, fwhm = 0.0, sigma = None, invert = False, pol = True, mmax = None, verbose = False, inplace = True): """Smooth alm with a Gaussian symmetric beam function. Parameters ---------- alms : array or sequence of 3 arrays Either an array representing one alm, or a sequence of arrays. See *pol* parameter. fwhm : float, optional The full width half max parameter of the Gaussian. Default:0.0 [in radians] sigma : float, optional The sigma of the Gaussian. Override fwhm. [in radians] invert : bool, optional If True, alms are divided by Gaussian beam function (un-smooth). Otherwise, alms are multiplied by Gaussian beam function (smooth). Default: False. pol : bool, optional If True, assumes input alms are TEB. Output will be TQU maps. (input must be 1 or 3 alms) If False, apply spin 0 harmonic transform to each alm. (input can be any number of alms) If there is only one input alm, it has no effect. Default: True. mmax : None or int, optional The maximum m for alm. Default: mmax=lmax inplace : bool, optional If True, the alm's are modified inplace if they are contiguous arrays of type complex128. Otherwise, a copy of alm is made. Default: True. verbose : bool, optional If True prints diagnostic information. Default: False Returns ------- alms : array or sequence of 3 arrays The smoothed alm. If alm[i] is a contiguous array of type complex128, and *inplace* is True the smoothing is applied inplace. Otherwise, a copy is made. """ if sigma is None: sigma = fwhm / (2.*np.sqrt(2.*np.log(2.))) if verbose: print "Sigma is %f arcmin (%f rad) " % (sigma*60*180/pi,sigma) print "-> fwhm is %f arcmin" % (sigma*60*180/pi*(2.*np.sqrt(2.*np.log(2.)))) # Check alms if not cb.is_seq(alms): raise ValueError("alm must be a sequence") if sigma == 0: # nothing to be done return alms lonely = False if not cb.is_seq_of_seq(alms): alms = [alms] lonely = True # we have 3 alms -> apply smoothing to each map. # polarization has different B_l from temperature # exp{-[ell(ell+1) - s**2] * sigma**2/2} # with s the spin of spherical harmonics # s = 2 for pol, s=0 for temperature retalm = [] for ialm, alm in enumerate(alms): lmax = Alm.getlmax(len(alm), mmax) if lmax < 0: raise TypeError('Wrong alm size for the given ' 'mmax (len(alms[%d]) = %d).'%(ialm, len(alm))) ell = np.arange(lmax + 1.) s = 2 if ialm >= 1 and pol else 0 fact = np.exp(-0.5 * (ell * (ell + 1) - s ** 2) * sigma ** 2) res = almxfl(alm, fact, mmax = mmax, inplace = inplace) retalm.append(res) # Test what to return (inplace/not inplace...) # Case 1: 1d input, return 1d output if lonely: return retalm[0] # case 2: 2d input, check if in-place smoothing for all alm's for i in xrange(len(alms)): samearray = alms[i] is retalm[i] if not samearray: # Case 2a: # at least one of the alm could not be smoothed in place: # return the list of alm return retalm # Case 2b: # all smoothing have been performed in place: # return the input alms return alms
def synalm(cls, lmax = None, mmax = None, new = False): """Generate a set of alm given cl. The cl are given as a float array. Corresponding alm are generated. If lmax is None, it is assumed lmax=cl.size-1 If mmax is None, it is assumed mmax=lmax. Parameters ---------- cls : float, array or tuple of arrays Either one cl (1D array) or a tuple of either 4 cl or of n*(n+1)/2 cl. Some of the cl may be None, implying no cross-correlation. See *new* parameter. lmax : int, scalar, optional The lmax (if None or <0, the largest size-1 of cls) mmax : int, scalar, optional The mmax (if None or <0, =lmax) new : bool, optional If True, use the new ordering of cl's, ie by diagonal (e.g. TT, EE, BB, TE, EB, TB or TT, EE, BB, TE if 4 cl as input). If False, use the old ordering, ie by row (e.g. TT, TE, TB, EE, EB, BB or TT, TE, EE, BB if 4 cl as input). Returns ------- alms : array or list of arrays the generated alm if one spectrum is given, or a list of n alms (with n(n+1)/2 the number of input cl, or n=3 if there are 4 input cl). Notes ----- The order of the spectra will change in a future release. The new= parameter help to make the transition smoother. You can start using the new order by setting new=True. In the next version of healpy, the default will be new=True. This change is done for consistency between the different tools (alm2cl, synfast, anafast). In the new order, the spectra are ordered by diagonal of the correlation matrix. Eg, if fields are T, E, B, the spectra are TT, EE, BB, TE, EB, TB with new=True, and TT, TE, TB, EE, EB, BB if new=False. """ if not new: warnings.warn("The order of the input cl's will change in a future " "release.\n" "Use new=True keyword to start using the new order.\n" "See documentation of healpy.synalm.", category=FutureChangeWarning) if not cb.is_seq(cls): raise TypeError('cls must be an array or a sequence of arrays') if not cb.is_seq_of_seq(cls): # Only one spectrum if lmax is None or lmax < 0: lmax = cls.size-1 if mmax is None or mmax < 0: mmax = lmax cls_list = [np.asarray(cls, dtype = np.float64)] szalm = Alm.getsize(lmax,mmax) alm = np.zeros(szalm,'D') alm.real = np.random.standard_normal(szalm) alm.imag = np.random.standard_normal(szalm) alms_list=[alm] sphtlib._synalm(cls_list,alms_list,lmax,mmax) return alm # From here, we interpret cls as a list of spectra cls_list = list(cls) maxsize = max([len(c) for c in cls]) if lmax is None or lmax < 0: lmax = maxsize-1 if mmax is None or mmax < 0: mmax = lmax Nspec = sphtlib._getn(len(cls_list)) if Nspec <= 0: if len(cls_list) == 4: if new: ## new input order: TT EE BB TE -> TT EE BB TE 0 0 cls_list = [cls[0], cls[1], cls[2], cls[3], None, None] else: ## old input order: TT TE EE BB -> TT TE 0 EE 0 BB cls_list = [cls[0], cls[1], None, cls[2], None, cls[3]] Nspec = 3 else: raise TypeError("The sequence of arrays must have either 4 elements " "or n(n+1)/2 elements (some may be None)") szalm = Alm.getsize(lmax,mmax) alms_list = [] for i in xrange(Nspec): alm = np.zeros(szalm,'D') alm.real = np.random.standard_normal(szalm) alm.imag = np.random.standard_normal(szalm) alms_list.append(alm) if new: # new input order: input given by diagonal, should be given by row cls_list = new_to_old_spectra_order(cls_list) # ensure cls are float64 cls_list = [(np.asarray(cl, dtype = np.float64) if cl is not None else None) for cl in cls_list] sphtlib._synalm(cls_list, alms_list, lmax, mmax) return alms_list
def alm2map(alms, nside, lmax = None, mmax = None, pixwin = False, fwhm = 0.0, sigma = None, invert = False, pol = True, inplace = False): """Computes an Healpix map given the alm. The alm are given as a complex array. You can specify lmax and mmax, or they will be computed from array size (assuming lmax==mmax). Parameters ---------- alms : complex, array or sequence of arrays A complex array or a sequence of complex arrays. Each array must have a size of the form: mmax * (2 * lmax + 1 - mmax) / 2 + lmax + 1 nside : int, scalar The nside of the output map. lmax : None or int, scalar, optional Explicitly define lmax (needed if mmax!=lmax) mmax : None or int, scalar, optional Explicitly define mmax (needed if mmax!=lmax) pixwin : bool, optional Smooth the alm using the pixel window functions. Default: False. fwhm : float, scalar, optional The fwhm of the Gaussian used to smooth the map (applied on alm) [in radians] sigma : float, scalar, optional The sigma of the Gaussian used to smooth the map (applied on alm) [in radians] invert : bool, optional If True, alms are divided by Gaussian beam function (un-smooth). Otherwise, alms are multiplied by Gaussian beam function (smooth). Default: False. pol : bool, optional If True, assumes input alms are TEB. Output will be TQU maps. (input must be 1 or 3 alms) If False, apply spin 0 harmonic transform to each alm. (input can be any number of alms) If there is only one input alm, it has no effect. Default: True. inplace : bool, optional If True, input alms may be modified by pixel window function and beam smoothing (if alm(s) are complex128 contiguous arrays). Otherwise, input alms are not modified. A copy is made if needed to apply beam smoothing or pixel window. Returns ------- maps : array or list of arrays An Healpix map in RING scheme at nside or a list of T,Q,U maps (if polarized input) """ if not cb.is_seq(alms): raise TypeError("alms must be a sequence") alms = smoothalm(alms, fwhm = fwhm, sigma = sigma, invert = invert, pol = pol, inplace = inplace) if not cb.is_seq_of_seq(alms): alms = [alms] lonely = True else: lonely = False if pixwin: pw = globals()['pixwin'](nside,True) alms_new = [] for ialm, alm in enumerate(alms): pixelwindow = pw[1] if ialm >= 1 and pol else pw[0] alms_new.append(almxfl(alm, pixelwindow, inplace = inplace)) else: alms_new = alms if lmax is None: lmax = -1 if mmax is None: mmax = -1 if pol: output = sphtlib._alm2map(alms_new[0] if lonely else alms_new, nside, lmax = lmax, mmax = mmax) if lonely: output = [output] else: output = [sphtlib._alm2map(alm, nside, lmax = lmax, mmax = mmax) for alm in alms_new] if lonely: return output[0] else: return output