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 lsst.sims.maf.metrics as metrics 

3import healpy as hp 

4from .seasonMetrics import calcSeason 

5from lsst.sims.photUtils import Dust_values 

6from lsst.sims.maf.utils import collapse_night 

7 

8__all__ = ['SNSLMetric'] 

9 

10 

11class SNSLMetric(metrics.BaseMetric): 

12 def __init__(self, metricName='SNSLMetric', 

13 mjdCol='observationStartMJD', RaCol='fieldRA', DecCol='fieldDec', 

14 filterCol='filter', exptimeCol='visitExposureTime', 

15 nightCol='night', obsidCol='observationId', nexpCol='numExposures', 

16 vistimeCol='visitTime', m5Col='fiveSigmaDepth', season=[-1], night_collapse=False, 

17 nfilters_min=4, min_season_obs=5, 

18 m5mins={'u': 22.7, 'g': 24.1, 'r': 23.7, 'i': 23.1, 'z': 22.2, 'y': 21.4}, 

19 maps=['DustMap'], **kwargs): 

20 """ 

21 Strongly Lensed SN metric 

22 

23 The number of is given by: 

24 

25 N (lensed SNe Ia with well measured time delay) = 45.7 * survey_area / 

26 (20000 deg^2) * cumulative_season_length / (2.5 years) / (2.15 * 

27 exp(0.37 * gap_median_all_filter)) 

28 

29 where: 

30 survey_area: survey area (in deg2) 

31 cumulative_season_length: cumulative season length (in years) 

32 gap_median_all_filter: median gap (all filters) 

33 

34 Parameters 

35 -------------- 

36 metricName : str, opt 

37 metric name 

38 Default : SNCadenceMetric 

39 mjdCol : str, opt 

40 mjd column name 

41 Default : observationStartMJD, 

42 RaCol : str,opt 

43 Right Ascension column name 

44 Default : fieldRa 

45 DecCol : str,opt 

46 Declinaison column name 

47 Default : fieldDec 

48 filterCol : str,opt 

49 filter column name 

50 Default: filter 

51 exptimeCol : str,opt 

52 exposure time column name 

53 Default : visitExposureTime 

54 nightCol : str,opt 

55 night column name 

56 Default : night 

57 obsidCol : str,opt 

58 observation id column name 

59 Default : observationId 

60 nexpCol : str,opt 

61 number of exposure column name 

62 Default : numExposures 

63 vistimeCol : str,opt 

64 visit time column name 

65 Default : visitTime 

66 season: int (list) or -1, opt 

67 season to process (default: -1: all seasons) 

68 nfilters_min : int (5) 

69 The number of filters to demand in a season 

70 

71 

72 """ 

73 self.mjdCol = mjdCol 

74 self.filterCol = filterCol 

75 self.RaCol = RaCol 

76 self.DecCol = DecCol 

77 self.exptimeCol = exptimeCol 

78 self.nightCol = nightCol 

79 self.obsidCol = obsidCol 

80 self.nexpCol = nexpCol 

81 self.vistimeCol = vistimeCol 

82 self.seasonCol = 'season' 

83 self.m5Col = m5Col 

84 self.maps= maps 

85 

86 cols = [self.nightCol, self.filterCol, self.mjdCol, self.obsidCol, 

87 self.nexpCol, self.vistimeCol, self.exptimeCol, self.m5Col] 

88 

89 super(SNSLMetric, self).__init__( 

90 col=cols, metricName=metricName, maps=self.maps, units='N SL', **kwargs) 

91 self.badVal = 0 

92 self.season = season 

93 self.bands = 'ugrizy' 

94 

95 self.night_collapse = night_collapse 

96 self.m5mins = m5mins 

97 self.min_season_obs = min_season_obs 

98 self.nfilters_min = nfilters_min 

99 self.phot_properties = Dust_values() 

100 

101 def run(self, dataSlice, slicePoint=None): 

102 """ 

103 Runs the metric for each dataSlice 

104 

105 Parameters 

106 --------------- 

107 dataSlice: simulation data 

108 slicePoint: slicePoint(default None) 

109 

110 Returns 

111 ----------- 

112 number of SL time delay supernovae 

113 

114 """ 

115 dataSlice.sort(order=self.mjdCol) 

116 

117 # Crop it down so things are coadded per night at the median MJD time 

118 dataSlice = collapse_night(dataSlice, nightCol=self.nightCol, filterCol=self.filterCol, 

119 m5Col=self.m5Col, mjdCol=self.mjdCol) 

120 

121 # get the pixel area 

122 area = hp.nside2pixarea(slicePoint['nside'], degrees=True) 

123 

124 if len(dataSlice) == 0: 

125 return self.badVal 

126 

127 season_id = np.floor(calcSeason(np.degrees(slicePoint['ra']), dataSlice[self.mjdCol])) 

128 

129 seasons = self.season 

130 

131 if self.season == [-1]: 

132 seasons = np.unique(season_id) 

133 

134 season_lengths = [] 

135 median_gaps = [] 

136 for season in seasons: 

137 idx = np.where(season_id == season)[0] 

138 bright_enough = np.zeros(idx.size, dtype=bool) 

139 for key in self.m5mins: 

140 in_filt = np.where(dataSlice[idx][self.filterCol] == key)[0] 

141 A_x = self.phot_properties.Ax1[key] * slicePoint['ebv'] 

142 bright_enough[in_filt[np.where((dataSlice[idx[in_filt]][self.m5Col] - A_x) > self.m5mins[key])[0]]] = True 

143 idx = idx[bright_enough] 

144 u_filters = np.unique(dataSlice[idx][self.filterCol]) 

145 if (len(idx) < self.min_season_obs) | (np.size(u_filters) < self.nfilters_min): 

146 continue 

147 if self.night_collapse: 

148 u_nights, unight_indx = np.unique(dataSlice[idx][self.nightCol], return_index=True) 

149 idx = idx[unight_indx] 

150 order = np.argsort(dataSlice[self.mjdCol][idx]) 

151 idx = idx[order] 

152 mjds_season = dataSlice[self.mjdCol][idx] 

153 cadence = mjds_season[1:]-mjds_season[:-1] 

154 season_lengths.append(mjds_season[-1]-mjds_season[0]) 

155 median_gaps.append(np.median(cadence)) 

156 

157 # get the cumulative season length 

158 

159 cumul_season_length = np.sum(season_lengths) 

160 

161 if cumul_season_length == 0: 

162 return self.badVal 

163 # get gaps 

164 gap_median = np.mean(median_gaps) 

165 

166 # estimate the number of lensed supernovae 

167 cumul_season = cumul_season_length/(12.*30.) 

168 

169 N_lensed_SNe_Ia = 45.7 * area / 20000. * cumul_season /\ 

170 2.5 / (2.15 * np.exp(0.37 * gap_median)) 

171 

172 return N_lensed_SNe_Ia 

173