Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""A slicer that uses a Healpix grid to calculate metric values (at the center of each healpixel).""" 

2 

3# Requires healpy 

4# See more documentation on healpy here http://healpy.readthedocs.org/en/latest/tutorial.html 

5# Also requires numpy (for histogram and power spectrum plotting) 

6 

7import numpy as np 

8import healpy as hp 

9from lsst.sims.maf.plots.spatialPlotters import HealpixSkyMap, HealpixHistogram, HealpixPowerSpectrum 

10 

11from .baseSpatialSlicer import BaseSpatialSlicer 

12 

13 

14__all__ = ['HealpixSlicer'] 

15 

16 

17class HealpixSlicer(BaseSpatialSlicer): 

18 """ 

19 A spatial slicer that evaluates pointings on a healpix-based grid. 

20 

21 Note that a healpix slicer is intended to evaluate the sky on a spatial grid. 

22 Usually this grid will be something like RA as the lonCol and Dec as the latCol. 

23 However, it could also be altitude and azimuth, in which case altitude as latCol, 

24 and azimuth as lonCol. 

25 An additional alternative is to use HA/Dec, with lonCol=HA, latCol=Dec. 

26 

27 When plotting with RA/Dec, the default HealpixSkyMap can be used, corresponding to 

28 {'rot': (0, 0, 0), 'flip': 'astro'}. 

29 When plotting with alt/az, either the LambertSkyMap can be used (if Basemap is installed) 

30 or the HealpixSkyMap can be used with a modified plotDict, 

31 {'rot': (90, 90, 90), 'flip': 'geo'}. 

32 When plotting with HA/Dec, only the HealpixSkyMap can be used, with a modified plotDict of 

33 {'rot': (0, -30, 0), 'flip': 'geo'}. 

34 

35 Parameters 

36 ---------- 

37 nside : int, optional 

38 The nside parameter of the healpix grid. Must be a power of 2. 

39 Default 128. 

40 lonCol : str, optional 

41 Name of the longitude (RA equivalent) column to use from the input data. 

42 Default fieldRA 

43 latCol : str, optional 

44 Name of the latitude (Dec equivalent) column to use from the input data. 

45 Default fieldDec 

46 latLonDeg : boolean, optional 

47 Flag indicating whether the lat and lon values in the input data are in 

48 degrees (True) or radians (False). 

49 Default True. 

50 verbose : boolean, optional 

51 Flag to indicate whether or not to write additional information to stdout during runtime. 

52 Default True. 

53 badval : float, optional 

54 Bad value flag, relevant for plotting. Default the hp.UNSEEN value (in order to properly flag 

55 bad data points for plotting with the healpix plotting routines). This should not be changed. 

56 useCache : boolean 

57 Flag allowing the user to indicate whether or not to cache (and reuse) metric results 

58 calculated with the same set of simulated data pointings. 

59 This can be safely set to True for slicers not using maps and will result in increased speed. 

60 When calculating metric results using maps, the metadata at each individual ra/dec point may 

61 influence the metric results and so useCache should be set to False. 

62 Default True. 

63 leafsize : int, optional 

64 Leafsize value for kdtree. Default 100. 

65 radius : float, optional 

66 Radius for matching in the kdtree. Equivalent to the radius of the FOV. Degrees. 

67 Default 1.75. 

68 useCamera : boolean, optional 

69 Flag to indicate whether to use the LSST camera footprint or not. 

70 Default False. 

71 rotSkyPosColName : str, optional 

72 Name of the rotSkyPos column in the input data. Only used if useCamera is True. 

73 Describes the orientation of the camera orientation compared to the sky. 

74 Default rotSkyPos. 

75 mjdColName : str, optional 

76 Name of the exposure time column. Only used if useCamera is True. 

77 Default observationStartMJD. 

78 chipNames : array-like, optional 

79 List of chips to accept, if useCamera is True. This lets users turn 'on' only a subset of chips. 

80 Default 'all' - this uses all chips in the camera. 

81 """ 

82 def __init__(self, nside=128, lonCol ='fieldRA', 

83 latCol='fieldDec', latLonDeg=True, verbose=True, badval=hp.UNSEEN, 

84 useCache=True, leafsize=100, radius=1.75, 

85 useCamera=False, rotSkyPosColName='rotSkyPos', 

86 mjdColName='observationStartMJD', chipNames='all'): 

87 """Instantiate and set up healpix slicer object.""" 

88 super(HealpixSlicer, self).__init__(verbose=verbose, 

89 lonCol=lonCol, latCol=latCol, 

90 badval=badval, radius=radius, leafsize=leafsize, 

91 useCamera=useCamera, rotSkyPosColName=rotSkyPosColName, 

92 mjdColName=mjdColName, chipNames=chipNames, latLonDeg=latLonDeg) 

93 # Valid values of nside are powers of 2. 

94 # nside=64 gives about 1 deg resolution 

95 # nside=256 gives about 13' resolution (~1 CCD) 

96 # nside=1024 gives about 3' resolution 

97 # Check validity of nside: 

98 if not(hp.isnsideok(nside)): 

99 raise ValueError('Valid values of nside are powers of 2.') 

100 self.nside = int(nside) 

101 self.pixArea = hp.nside2pixarea(self.nside) 

102 self.nslice = hp.nside2npix(self.nside) 

103 self.spatialExtent = [0, self.nslice-1] 

104 self.shape = self.nslice 

105 if self.verbose: 

106 print('Healpix slicer using NSIDE=%d, ' % (self.nside) + \ 

107 'approximate resolution %f arcminutes' % (hp.nside2resol(self.nside, arcmin=True))) 

108 # Set variables so slicer can be re-constructed 

109 self.slicer_init = {'nside': nside, 'lonCol': lonCol, 'latCol': latCol, 

110 'radius': radius} 

111 self.useCache = useCache 

112 if useCache: 

113 # useCache set the size of the cache for the memoize function in sliceMetric. 

114 binRes = hp.nside2resol(nside) # Pixel size in radians 

115 # Set the cache size to be ~2x the circumference 

116 self.cacheSize = int(np.round(4.*np.pi/binRes)) 

117 # Set up slicePoint metadata. 

118 self.slicePoints['nside'] = nside 

119 self.slicePoints['sid'] = np.arange(self.nslice) 

120 self.slicePoints['ra'], self.slicePoints['dec'] = self._pix2radec(self.slicePoints['sid']) 

121 # Set the default plotting functions. 

122 self.plotFuncs = [HealpixSkyMap, HealpixHistogram, HealpixPowerSpectrum] 

123 

124 def __eq__(self, otherSlicer): 

125 """Evaluate if two slicers are equivalent.""" 

126 # If the two slicers are both healpix slicers, check nsides value. 

127 result = False 

128 if isinstance(otherSlicer, HealpixSlicer): 

129 if otherSlicer.nside == self.nside: 

130 if (otherSlicer.lonCol == self.lonCol and otherSlicer.latCol == self.latCol): 

131 if otherSlicer.radius == self.radius: 

132 if otherSlicer.useCamera == self.useCamera: 

133 if otherSlicer.chipsToUse == self.chipsToUse: 

134 if otherSlicer.rotSkyPosColName == self.rotSkyPosColName: 

135 if np.all(otherSlicer.shape == self.shape): 

136 if otherSlicer.useCache == self.useCache: 

137 result = True 

138 return result 

139 

140 def _pix2radec(self, islice): 

141 """Given the pixel number / sliceID, return the RA/Dec of the pointing, in radians.""" 

142 # Calculate RA/Dec in RADIANS of pixel in this healpix slicer. 

143 # Note that ipix could be an array, 

144 # in which case RA/Dec values will be an array also. 

145 lat, ra = hp.pix2ang(self.nside, islice) 

146 # Move dec to +/- 90 degrees 

147 dec = np.pi/2.0 - lat 

148 return ra, dec