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

1import numpy as np 

2import healpy as hp 

3import warnings 

4from scipy.stats import binned_statistic 

5from lsst.sims.utils import int_binned_stat 

6 

7 

8__all__ = ['optimalBins', 'percentileClipping', 

9 'gnomonic_project_toxy', 'radec2pix', 'collapse_night'] 

10 

11 

12def coaddM5(mags): 

13 """Coadded depth, assuming Gaussian noise 

14 """ 

15 return 1.25 * np.log10(np.sum(10.**(0.8*np.array(mags)))) 

16 

17 

18def collapse_night(dataSlice, nightCol='night', filterCol='filter', 

19 m5Col='fiveSigmaDepth', mjdCol='observationStartMJD'): 

20 """Collapse a dataSlice down by night. Convert the MJD to the median MJD per night and coadd 5-sigma depth (per filter) 

21 """ 

22 # Make an explicit copy so we don't clobber things 

23 result = dataSlice.copy() 

24 result.sort(order=[nightCol, filterCol]) 

25 

26 filters = np.unique(result[filterCol]) 

27 

28 for filtername in filters: 

29 infilt = np.where(result[filterCol] == filtername)[0] 

30 unight, indices = np.unique(result[nightCol][infilt], return_inverse=True) 

31 right = unight+0.5 

32 bins = [unight[0]-0.5] + right.tolist() 

33 coadds, be, bn = binned_statistic(result[nightCol][infilt], 

34 result[m5Col][infilt], bins=bins, 

35 statistic=coaddM5) 

36 # now we just clobber the m5Col with the coadd for the night 

37 result[m5Col][infilt] = coadds[indices] 

38 

39 unights, median_mjd_per_night = int_binned_stat(dataSlice[nightCol][infilt], 

40 dataSlice[mjdCol][infilt], 

41 statistic=np.median) 

42 dataSlice[mjdCol][infilt] = median_mjd_per_night[indices] 

43 

44 # Note, we could also clobber exposure MJD, exposure time, etc. But I don't think they 

45 # get used later, so maybe OK. 

46 

47 # Make a string that is the combination of night and filter 

48 night_filt = np.char.add(dataSlice[nightCol].astype(str), dataSlice[filterCol].astype(str)) 

49 u_nf, indx = np.unique(night_filt, return_index=True) 

50 dataSlice = dataSlice[indx] 

51 dataSlice.sort(order=[mjdCol]) 

52 

53 return dataSlice 

54 

55 

56 

57def optimalBins(datain, binmin=None, binmax=None, nbinMax=200, nbinMin=1): 

58 """ 

59 Set an 'optimal' number of bins using the Freedman-Diaconis rule. 

60 

61 Parameters 

62 ---------- 

63 datain : numpy.ndarray or numpy.ma.MaskedArray 

64 The data for which we want to set the binsize. 

65 binmin : float 

66 The minimum bin value to consider (if None, uses minimum data value). 

67 binmax : float 

68 The maximum bin value to consider (if None, uses maximum data value). 

69 nbinMax : int 

70 The maximum number of bins to create. Sometimes the 'optimal binsize' implies 

71 an unreasonably large number of bins, if the data distribution is unusual. 

72 nbinMin : int 

73 The minimum number of bins to create. Default is 1. 

74 

75 Returns 

76 ------- 

77 int 

78 The number of bins. 

79 """ 

80 # if it's a masked array, only use unmasked values 

81 if hasattr(datain, 'compressed'): 

82 data = datain.compressed() 

83 else: 

84 data = datain 

85 # Check that any good data values remain. 

86 if data.size == 0: 

87 nbins = nbinMax 

88 warnings.warn('No unmasked data available for calculating optimal bin size: returning %i bins' %(nbins)) 

89 # Else proceed. 

90 else: 

91 if binmin is None: 

92 binmin = np.nanmin(data) 

93 if binmax is None: 

94 binmax = np.nanmax(data) 

95 cond = np.where((data >= binmin) & (data <= binmax))[0] 

96 # Check if any data points remain within binmin/binmax. 

97 if np.size(data[cond]) == 0: 

98 nbins = nbinMax 

99 warnings.warn('No data available for calculating optimal bin size within range of %f, %f' 

100 %(binmin, binmax) + ': returning %i bins' %(nbins)) 

101 else: 

102 iqr = np.percentile(data[cond], 75) - np.percentile(data[cond], 25) 

103 binwidth = 2 * iqr * (np.size(data[cond])**(-1./3.)) 

104 nbins = (binmax - binmin) / binwidth 

105 if nbins > nbinMax: 

106 warnings.warn('Optimal bin calculation tried to make %.0f bins, returning %i'%(nbins, nbinMax)) 

107 nbins = nbinMax 

108 if nbins < nbinMin: 

109 warnings.warn('Optimal bin calculation tried to make %.0f bins, returning %i'%(nbins, nbinMin)) 

110 nbins = nbinMin 

111 if np.isnan(nbins): 

112 warnings.warn('Optimal bin calculation calculated NaN: returning %i' %(nbinMax)) 

113 nbins = nbinMax 

114 return int(nbins) 

115 

116 

117def percentileClipping(data, percentile=95.): 

118 """ 

119 Calculate the minimum and maximum values of a distribution of points, after 

120 discarding data more than 'percentile' from the median. 

121 This is useful for determining useful data ranges for plots. 

122 Note that 'percentile' percent of the data is retained. 

123 

124 Parameters 

125 ---------- 

126 data : numpy.ndarray 

127 The data to clip. 

128 percentile : float 

129 Retain values within percentile of the median. 

130 

131 Returns 

132 ------- 

133 float, float 

134 The minimum and maximum values of the clipped data. 

135 """ 

136 lower_percentile = (100 - percentile) / 2.0 

137 upper_percentile = 100 - lower_percentile 

138 min_value = np.percentile(data, lower_percentile) 

139 max_value = np.percentile(data, upper_percentile) 

140 return min_value, max_value 

141 

142def gnomonic_project_toxy(RA1, Dec1, RAcen, Deccen): 

143 """ 

144 Calculate the x/y values of RA1/Dec1 in a gnomonic projection with center at RAcen/Deccen. 

145 

146 Parameters 

147 ---------- 

148 RA1 : numpy.ndarray 

149 RA values of the data to be projected, in radians. 

150 Dec1 : numpy.ndarray 

151 Dec values of the data to be projected, in radians. 

152 RAcen: float 

153 RA value of the center of the projection, in radians. 

154 Deccen : float 

155 Dec value of the center of the projection, in radians. 

156 

157 Returns 

158 ------- 

159 numpy.ndarray, numpy.ndarray 

160 The x/y values of the projected RA1/Dec1 positions. 

161 """ 

162 cosc = np.sin(Deccen) * np.sin(Dec1) + np.cos(Deccen) * np.cos(Dec1) * np.cos(RA1-RAcen) 

163 x = np.cos(Dec1) * np.sin(RA1-RAcen) / cosc 

164 y = (np.cos(Deccen)*np.sin(Dec1) - np.sin(Deccen)*np.cos(Dec1)*np.cos(RA1-RAcen)) / cosc 

165 return x, y 

166 

167 

168def radec2pix(nside, ra, dec): 

169 """ 

170 Calculate the nearest healpixel ID of an RA/Dec array, assuming nside. 

171 

172 Parameters 

173 ---------- 

174 nside : int 

175 The nside value of the healpix grid. 

176 ra : numpy.ndarray 

177 The RA values to be converted to healpix ids, in radians. 

178 dec : numpy.ndarray 

179 The Dec values to be converted to healpix ids, in radians. 

180 

181 Returns 

182 ------- 

183 numpy.ndarray 

184 The healpix ids. 

185 """ 

186 lat = np.pi/2. - dec 

187 hpid = hp.ang2pix(nside, lat, ra ) 

188 return hpid