/healpy/sphtfunc.py

http://healpy.googlecode.com/ · Python · 508 lines · 466 code · 3 blank · 39 comment · 13 complexity · df652c988f28af69bbbbce46120bae27 MD5 · raw file

  1. #
  2. # This file is part of Healpy.
  3. #
  4. # Healpy is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # Healpy is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with Healpy; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. #
  18. # For more information about Healpy, see http://code.google.com/p/healpy
  19. #
  20. import numpy as npy
  21. import _healpy_sph_transform_lib as sphtlib
  22. import _healpy_fitsio_lib as hfitslib
  23. import os.path
  24. import pixelfunc
  25. pi = npy.pi
  26. DATAPATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data')
  27. # Spherical harmonics transformation
  28. def anafast(m,lmax=None,mmax=None,iter=1,alm=False, use_weights=False, regression=True):
  29. """Computes the power spectrum of an Healpix map.
  30. Input:
  31. - m : either an array representing a map, or a list of 3 arrays
  32. representing I, Q, U maps
  33. Parameters:
  34. - lmax : maximum l of the power spectrum (default: 3*nside-1)
  35. - mmax : maximum m of the alm (default: lmax)
  36. - iter : number of iteration (default: 1)
  37. - alm : (boolean) whether to return alm or not (if True, both are
  38. returned in a tuple)
  39. - regression : if True, map average is removed before computing alm. Default: True.
  40. Return:
  41. - if alm==False: return cl or a list of cl's (TT,EE,BB,TE)
  42. - if alm==True: return a tuple with cl or a list of cl's and alm
  43. or a list of alm's
  44. """
  45. datapath = DATAPATH #os.path.dirname(__file__)+'/data'
  46. nside = _get_nside(m)
  47. if lmax is None:
  48. lmax = 3*nside-1
  49. if mmax is None or mmax < 0 or mmax > lmax:
  50. mmax = lmax
  51. # Check the presence of weights file
  52. if use_weights:
  53. weightfile = 'weight_ring_n%05d.fits' % (nside)
  54. if not os.path.isfile(datapath+'/'+weightfile):
  55. raise IOError('File not found : '+datapath+'/'+weightfile)
  56. clout,almout = sphtlib._map2alm(m,lmax=lmax,mmax=mmax,iter=iter,cl=True,
  57. use_weights=use_weights,data_path=datapath,
  58. regression=regression)
  59. if alm:
  60. return (clout,almout)
  61. else:
  62. return clout
  63. def map2alm(m,lmax=None,mmax=None,iter=1,use_weights=False,regression=True):
  64. """Computes the alm of an Healpix map.
  65. Input:
  66. - m: a ndarray (not polarized) or a list of 3 ndarray (polarized)
  67. Parameters:
  68. - lmax : maximum l of the power spectrum. Default: 3*nside-1
  69. - mmax : maximum m of the alm. Default: lmax
  70. - iter : number of iteration (default: 1)
  71. - use_weights: whether to use ring weights or not. Default: False.
  72. - regression: if True, subtract map average before computing alm. Default: True.
  73. Return:
  74. - alm as one ndarray or a tuple of 3 ndarrays
  75. """
  76. datapath = DATAPATH #os.path.dirname(__file__)+'/data'
  77. nside = _get_nside(m)
  78. if lmax is None:
  79. lmax = 3*nside-1
  80. if mmax is None or mmax < 0 or mmax > lmax:
  81. mmax = lmax
  82. # Check the presence of weights file
  83. if use_weights:
  84. weightfile = 'weight_ring_n%05d.fits' % (nside)
  85. if not os.path.isfile(datapath+'/'+weightfile):
  86. raise IOError('File not found : '+datapath+'/'+weightfile)
  87. alm = sphtlib._map2alm(m,lmax=lmax,mmax=mmax,cl=False,
  88. iter=iter,
  89. use_weights=use_weights,data_path=datapath,
  90. regression=regression)
  91. return alm
  92. def alm2map(alm, nside, lmax=-1, mmax=-1,pixwin=False,
  93. fwhm=0.0,sigma=None,degree=False,arcmin=False):
  94. """Computes an Healpix map given the alm.
  95. The alm are given as a complex array. You can specify lmax
  96. and mmax, or they will be computed from array size (assuming
  97. lmax==mmax).
  98. Parameters:
  99. - alm: a complex array of alm. Size must be of the form
  100. size=mmax(lmax-mmax+1)/2+lmax
  101. - nside: the nside of the output map.
  102. - lmax: explicitly define lmax (needed if mmax!=lmax)
  103. - mmax: explicitly define mmax (needed if mmax!=lmax)
  104. - fwhm, sigma, degree and arcmin (as in smoothalm): smooth by a Gaussian
  105. symmetric beam
  106. Return: an Healpix map in RING scheme at nside.
  107. """
  108. smoothalm(alm,fwhm=fwhm,sigma=sigma,degree=degree,arcmin=arcmin)
  109. if pixwin:
  110. pw=globals()['pixwin'](nside,True)
  111. if type(alm[0]) is npy.ndarray:
  112. if len(alm) != 3:
  113. raise TypeError("alm must be a sequence of 3 ndarray "
  114. "or a 1D ndarray")
  115. alm[0] = almxfl(alm[0],pw[0],inplace=True)
  116. alm[1] = almxfl(alm[1],pw[1],inplace=True)
  117. alm[2] = almxfl(alm[2],pw[1],inplace=True)
  118. else:
  119. alm = almxfl(alm,pw[0],inplace=True)
  120. return sphtlib._alm2map(alm,nside,lmax=lmax,mmax=mmax)
  121. def synalm(cls, lmax=-1, mmax=-1):
  122. """Generate a set of alm given cl.
  123. The cl are given as a float array. Corresponding alm are generated.
  124. If lmax is not given or negative, it is assumed lmax=cl.size-1
  125. If mmax is not given or negative, it is assumed mmax=lmax.
  126. Call: alms = synalm(cls, lmax=-1, mmax=-1)
  127. Input:
  128. - cls: either one cl (1D array) or a tuple of either 4 cl (TT,TE,EE,BB)
  129. or of n(n+1)/2 cl. Some of the cl may be None, implying no
  130. cross-correlation. For example, (TT,TE,TB,EE,EB,BB).
  131. NOTE: this order differs from the alm2cl function !
  132. Parameters:
  133. - lmax: the lmax (if <0, the largest size-1 of cls)
  134. - mmax: the mmax (if <0, =lmax)
  135. Return: a list of n alms (with n(n+1)/2 the number of input cl,
  136. or n=3 if there are 4 input cl).
  137. """
  138. if not isinstance(cls[0], npy.ndarray):
  139. if lmax < 0: lmax = cls.size-1
  140. if mmax < 0: mmax = lmax
  141. cls_list = [cls]
  142. szalm = Alm.getsize(lmax,mmax)
  143. alm = npy.zeros(szalm,'D')
  144. alm.real = npy.random.standard_normal(szalm)
  145. alm.imag = npy.random.standard_normal(szalm)
  146. alms_list=[alm]
  147. sphtlib._synalm(cls_list,alms_list,lmax,mmax)
  148. return alm
  149. # otherwise, cls must be a sequence of arrays
  150. try:
  151. cls_list = list(cls)
  152. maxsize = 0
  153. for c in cls_list:
  154. if c is not None:
  155. if c.size > maxsize: maxsize=c.size
  156. except:
  157. raise TypeError("First argument must be an array or a sequence of arrays.")
  158. if lmax < 0: lmax = maxsize-1
  159. if mmax < 0: mmax = lmax
  160. if sphtlib._getn(len(cls_list)) <= 0:
  161. if len(cls_list) == 4: # if 4 cls are given, assume TT, TE, EE, BB
  162. cls_list = [cls[0], cls[1], None, cls[2], None, cls[3]]
  163. else:
  164. raise TypeError("The sequence of arrays must have either 4 elements "
  165. "(TT,TE,EE,BB)\n"
  166. "or n(n+1)/2 elements (some may be None)")
  167. szalm = Alm.getsize(lmax,mmax)
  168. alms_list = []
  169. for i in xrange(sphtlib._getn(len(cls_list))):
  170. alm = npy.zeros(szalm,'D')
  171. alm.real = npy.random.standard_normal(szalm)
  172. alm.imag = npy.random.standard_normal(szalm)
  173. alms_list.append(alm)
  174. sphtlib._synalm(cls_list, alms_list, lmax, mmax)
  175. if len(alms_list) > 1:
  176. return alms_list
  177. else:
  178. return alms_list[0]
  179. def synfast(cls,nside,lmax=-1,mmax=-1,alm=False,
  180. pixwin=False,fwhm=0.0,sigma=None,degree=False,
  181. arcmin=False):
  182. """Create a map(s) from cl(s).
  183. Input:
  184. - cls: an array of cl or a list of cls (either 4 or 6, see synalm)
  185. - nside: the nside of the output map(s)
  186. Parameters:
  187. - lmax, mmax: maximum l and m for alm. Default: 3*nside-1
  188. - alm : if True, return also alm(s). Default: False.
  189. - pixwin: convolve the alm by the pixel window function. Default: False.
  190. - fwhm,sigma,degree,arcmin: see smoothalm. Convolve the map(s)
  191. by a symmetric Gaussian beam
  192. Output:
  193. - if alm==False: return a map or a tuple of maps
  194. - if alm==True: return a tuple of map(s) and alm(s)
  195. """
  196. if not pixelfunc.isnsideok(nside):
  197. raise ValueError("Wrong nside value (must be a power of two).")
  198. if lmax < 0:
  199. lmax = 3*nside-1
  200. alms = synalm(cls,lmax,mmax)
  201. maps = alm2map(alms,nside,lmax,mmax,pixwin=pixwin,
  202. fwhm=fwhm,sigma=sigma,degree=degree,
  203. arcmin=arcmin)
  204. if alm: return maps,alms
  205. else: return maps
  206. class Alm(object):
  207. """This class provides some static methods for alm index computation.
  208. * getlm(lmax,i=None)
  209. * getidx(lmax,l,m)
  210. * getsize(lmax,mmax=-1)
  211. * getlmax(s,mmax=-1)
  212. """
  213. def __init__(self,lmax):
  214. pass
  215. @staticmethod
  216. def getlm(lmax,i=None):
  217. """Get the l and m from index and lmax.
  218. Parameters:
  219. - lmax
  220. - i: the index. If not given, the function return l and m
  221. for i=0..Alm.getsize(lmax)
  222. """
  223. if i is None:
  224. i=npy.arange(Alm.getsize(lmax))
  225. m=(npy.ceil(((2*lmax+1)-npy.sqrt((2*lmax+1)**2-8*(i-lmax)))/2)).astype(int)
  226. l = i-m*(2*lmax+1-m)/2
  227. return (l,m)
  228. @staticmethod
  229. def getidx(lmax,l,m):
  230. """Get index from lmax, l and m.
  231. Parameters:
  232. - lmax
  233. - l
  234. - m
  235. """
  236. return m*(2*lmax+1-m)/2+l
  237. @staticmethod
  238. def getsize(lmax,mmax=-1):
  239. if mmax<0 or mmax > lmax:
  240. mmax=lmax
  241. return mmax*(2*lmax+1-mmax)/2+lmax+1
  242. @staticmethod
  243. def getlmax(s,mmax=-1):
  244. if mmax >= 0:
  245. x=(2*s+mmax**2-mmax-2)/(2*mmax+2)
  246. else:
  247. x=(-3+npy.sqrt(1+8*s))/2
  248. if x != npy.floor(x):
  249. return -1
  250. else:
  251. return int(x)
  252. def alm2cl(alm,mmax=-1,nspec=4):
  253. """Compute the auto- and cross- spectra of the given alm's
  254. (either 1 alm or 3 alm).
  255. Input:
  256. - alm: one array or a sequence of 3 arrays of identical size
  257. Parameters:
  258. - mmax: maximum m for alm(s)
  259. - nspec: number of spectra to return if 3 alms were given:
  260. nspec==[0-6], in order TT,EE,BB,TE,TB,EB.
  261. """
  262. # this is the expected lmax, given mmax
  263. if isinstance(alm,npy.ndarray) and alm.ndim == 1:
  264. lmax = Alm.getlmax(alm.size,mmax)
  265. if lmax < 0:
  266. raise TypeError('Wrong alm size for the given mmax.')
  267. if mmax<0:
  268. mmax=lmax
  269. cl_est = npy.zeros(lmax+1)
  270. for l in range(lmax+1):
  271. i=Alm.getidx(lmax,l,npy.arange(min(mmax,l)+1))
  272. cl_est[l] = (npy.abs(alm[i[0]])**2
  273. +2.*npy.sum(npy.abs(alm[i[1:]])**2))/(2*l+1)
  274. return cl_est
  275. else:
  276. almT,almE,almB=tuple(alm)
  277. lmax = Alm.getlmax(almT.size,mmax)
  278. if lmax < 0:
  279. raise TypeError('Wrong alm size for the given mmax.')
  280. if mmax<0:
  281. mmax=lmax
  282. ctt_est = npy.zeros(lmax+1)
  283. cee_est = npy.zeros(lmax+1)
  284. cbb_est = npy.zeros(lmax+1)
  285. cte_est = npy.zeros(lmax+1)
  286. ctb_est = npy.zeros(lmax+1)
  287. ceb_est = npy.zeros(lmax+1)
  288. for l in range(lmax+1):
  289. i=Alm.getidx(lmax,l,npy.arange(min(mmax,l)+1))
  290. ctt_est[l] = (npy.abs(almT[i[0]])**2
  291. +2.*npy.sum(npy.abs(almT[i[1:]])**2))/(2*l+1)
  292. cee_est[l] = (npy.abs(almE[i[0]])**2
  293. +2.*npy.sum(npy.abs(almE[i[1:]])**2))/(2*l+1)
  294. cbb_est[l] = (npy.abs(almB[i[0]])**2
  295. +2.*npy.sum(npy.abs(almB[i[1:]])**2))/(2*l+1)
  296. cte_est[l] = (almT[i[0]]*almE[i[0]].conj()
  297. +2.*npy.sum(almT[i[1:]]*almE[i[1:]].conj()))/(2*l+1)
  298. ctb_est[l] = (almT[i[0]]*almB[i[0]].conj()
  299. +2.*npy.sum(almT[i[1:]]*almB[i[1:]].conj()))/(2*l+1)
  300. ceb_est[l] = (almE[i[0]]*almB[i[0]].conj()
  301. +2.*npy.sum(almE[i[1:]]*almB[i[1:]].conj()))/(2*l+1)
  302. return (ctt_est,cee_est,cbb_est,cte_est,ctb_est,ceb_est)[:nspec]
  303. def almxfl(alm,fl,mmax=-1,inplace=False):
  304. """Multiply alm by a function of l. The function is assumed
  305. to be zero where not defined.
  306. If inplace is True, the operation is done in place. Always return
  307. the alm array (either a new array or the modified input array).
  308. """
  309. # this is the expected lmax, given mmax
  310. lmax = Alm.getlmax(alm.size,mmax)
  311. if lmax < 0:
  312. raise TypeError('Wrong alm size for the given mmax.')
  313. if mmax<0:
  314. mmax=lmax
  315. fl = npy.array(fl)
  316. if inplace:
  317. almout = alm
  318. else:
  319. almout = alm.copy()
  320. for l in range(lmax+1):
  321. if l < fl.size:
  322. a=fl[l]
  323. else:
  324. a=0
  325. i=Alm.getidx(lmax,l,npy.arange(min(mmax,l)+1))
  326. almout[i] *= a
  327. return almout
  328. def smoothalm(alm,fwhm=0.0,sigma=None,degree=False,
  329. arcmin=False,mmax=-1,verbose=False):
  330. """Smooth alm with a Gaussian symmetric beam function in place.
  331. Input:
  332. - alm: either an array representing one alm, or a sequence of
  333. 3 arrays representing 3 alm
  334. Parameters:
  335. - fwhm: the full width half max parameter of the Gaussian. Default:0.0
  336. - sigma: the sigma of the Gaussian. Override fwhm.
  337. - degree: if True, parameter given in degree. Override arcmin.
  338. Default: False
  339. - arcmin: if True, parameter given in arcmin. Default: False
  340. - mmax: the maximum m for alm. Default: mmax=lmax
  341. - verbose: if True prints diagnostic information. Default: False
  342. Return:
  343. None
  344. """
  345. if sigma is None:
  346. sigma = fwhm / (2.*npy.sqrt(2.*npy.log(2.)))
  347. if degree:
  348. sigma *= (pi/180.)
  349. elif arcmin:
  350. sigma *= (pi/180./60.)
  351. if verbose:
  352. print "Sigma is %f arcmin (%f rad) " % (sigma*60*180/pi,sigma)
  353. print "-> fwhm is %f arcmin" % (sigma*60*180/pi*(2.*npy.sqrt(2.*npy.log(2.))))
  354. if type(alm[0]) == npy.ndarray:
  355. if len(alm) != 3:
  356. raise ValueError("alm must be en array or a sequence of 3 arrays")
  357. retval = []
  358. for a in alm:
  359. lmax = Alm.getlmax(a.size,mmax)
  360. if lmax < 0:
  361. raise TypeError('Wrong alm size for the given '
  362. 'mmax (alms[%d]).'%(a.size))
  363. if mmax<0:
  364. mmax=lmax
  365. ell = npy.arange(lmax+1)
  366. fact = npy.exp(-0.5*ell*(ell+1)*sigma**2)
  367. almxfl(a,fact,mmax,inplace=True)
  368. return None
  369. else:
  370. lmax = Alm.getlmax(alm.size,mmax)
  371. if lmax < 0:
  372. raise TypeError('Wrong alm size for the given '
  373. 'mmax (alms[%d]).'%(a.size))
  374. if mmax<0:
  375. mmax=lmax
  376. ell = npy.arange(lmax+1)
  377. fact = npy.exp(-0.5*ell*(ell+1)*sigma**2)
  378. almxfl(alm,fact,mmax,inplace=True)
  379. return None
  380. def smoothing(m,fwhm=0.0,sigma=None,degree=False,
  381. arcmin=False):
  382. """Smooth a map with a Gaussian symmetric beam.
  383. Input:
  384. - map: either an array representing one map, or a sequence of
  385. 3 arrays representing 3 maps
  386. Parameters:
  387. - fwhm: the full width half max parameter of the Gaussian. Default:0.0
  388. - sigma: the sigma of the Gaussian. Override fwhm.
  389. - degree: if True, parameter given in degree. Override arcmin.
  390. Default: False
  391. - arcmin: if True, parameter given in arcmin. Default: False
  392. - mmax: the maximum m for alm. Default: mmax=lmax
  393. Return:
  394. - the smoothed map(s)
  395. """
  396. if type(m[0]) is npy.ndarray:
  397. if len(m) != 3:
  398. raise TypeError("map must be en array or a list of 3 arrays")
  399. nside = pixelfunc.npix2nside(m[0].size)
  400. if (pixelfunc.npix2nside(m[1].size) != nside
  401. or pixelfunc.npix2nside(m[2].size) != nside):
  402. raise TypeError("all maps in the array must have identical nside")
  403. elif type(m) == npy.ndarray:
  404. nside=pixelfunc.npix2nside(m.size)
  405. else:
  406. raise TypeError("map must be en array or a list of 3 arrays")
  407. alm = map2alm(m)
  408. return alm2map(alm,nside,fwhm=fwhm,sigma=sigma,
  409. degree=degree,arcmin=arcmin)
  410. def pixwin(nside,pol=False):
  411. """Return the pixel window function for the given nside.
  412. Input:
  413. - nside
  414. Parameters:
  415. - pol: if True, return also the polar pixel window. Default: False
  416. Return:
  417. - the temperature pixel window function, or a tuple with both
  418. temperature and polarisation pixel window functions.
  419. """
  420. datapath = DATAPATH
  421. if not pixelfunc.isnsideok(nside):
  422. raise ValueError("Wrong nside value (must be a power of two).")
  423. fname = os.path.join(datapath, 'pixel_window_n%04d.fits'%nside)
  424. if not os.path.isfile(fname):
  425. raise ValueError("No pixel window for this nside "
  426. "or data files missing")
  427. # return hfitslib._pixwin(nside,datapath,pol) ## BROKEN -> seg fault...
  428. try:
  429. import pyfits
  430. except ImportError:
  431. print "*********************************************************"
  432. print "** You need to install pyfits to use this function **"
  433. print "*********************************************************"
  434. raise
  435. pw = pyfits.getdata(fname)
  436. pw_temp, pw_pol = pw.field(0), pw.field(1)
  437. if pol:
  438. return pw_temp, pw_pol
  439. else:
  440. return pw_temp
  441. def alm2map_der1(alm, nside, lmax=-1, mmax=-1):
  442. """Computes an Healpix map and its first derivatives given the alm.
  443. The alm are given as a complex array. You can specify lmax
  444. and mmax, or they will be computed from array size (assuming
  445. lmax==mmax).
  446. Parameters:
  447. - alm: a complex array of alm. Size must be of the form
  448. size=mmax(lmax-mmax+1)/2+lmax
  449. - nside: the nside of the output map.
  450. - lmax: explicitly define lmax (needed if mmax!=lmax)
  451. - mmax: explicitly define mmax (needed if mmax!=lmax)
  452. Return: an Healpix map in RING scheme at nside.
  453. """
  454. return sphtlib._alm2map_der1(alm,nside,lmax=lmax,mmax=mmax)
  455. # Helper function : get nside from m, an array or a sequence
  456. # of arrays
  457. def _get_nside(m):
  458. if hasattr(m,'__len__'):
  459. if len(m) == 0:
  460. raise TypeError('Empty sequence !')
  461. if hasattr(m[0],'__len__'):
  462. nside=pixelfunc.npix2nside(len(m[0]))
  463. else:
  464. nside=pixelfunc.npix2nside(len(m))
  465. else:
  466. raise TypeError('You must give an array or a tuple of arrays '
  467. 'as input')
  468. return nside