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 matplotlib.pyplot as plt 

3from scipy import interpolate 

4import numpy.lib.recfunctions as rf 

5 

6 

7class Lims: 

8 """ 

9 class to handle light curve of SN 

10 

11 Parameters 

12 --------------- 

13 Li_files : str 

14 light curve reference file 

15 mag_to_flux_files : str 

16 files of magnitude to flux 

17 band : str 

18 band considered 

19 SNR : float 

20 Signal-To-Noise Ratio cut 

21 mag_range : pair(float),opt 

22 mag range considered 

23 Default : (23., 27.5) 

24 dt_range : pair(float) 

25 difference time range considered (cadence) 

26 Default : (0.5, 25.) 

27 """ 

28 

29 def __init__(self, Li_files, mag_to_flux_files, band, SNR, 

30 mag_range=(23., 27.5), dt_range=(0.5, 25.)): 

31 

32 self.band = band 

33 self.SNR = SNR 

34 self.lims = [] 

35 self.mag_to_flux = [] 

36 self.mag_range = mag_range 

37 self.dt_range = dt_range 

38 

39 for val in Li_files: 

40 self.lims.append(self.get_lims(self.band, np.load(val), SNR)) 

41 for val in mag_to_flux_files: 

42 self.mag_to_flux.append(np.load(val)) 

43 self.interp() 

44 

45 def get_lims(self, band, tab, SNR): 

46 """ 

47 Estimations of the limits 

48 

49 Parameters 

50 --------------- 

51 band : str 

52 band to consider 

53 tab : numpy array 

54 table of data 

55 SNR : float 

56 Signal-to-Noise Ratio cut 

57 

58 Returns: 

59 ----------- 

60 dict of limits with redshift and band as keys. 

61 

62 """ 

63 

64 lims = {} 

65 

66 for z in np.unique(tab['z']): 

67 

68 idx = (tab['z'] == z) & (tab['band'] == 'LSST::'+band) 

69 idx &= (tab['flux_e'] > 0.) 

70 sel = tab[idx] 

71 

72 if len(sel) > 0: 

73 li2 = np.sqrt(np.sum(sel['flux_e']**2)) 

74 lim = 5. * li2 / SNR 

75 if z not in lims.keys(): 

76 lims[z] = {} 

77 lims[z][band] = lim 

78 

79 return lims 

80 

81 def mesh(self, mag_to_flux): 

82 """ 

83 Mesh grid to estimate five-sigma depth values (m5) from mags input. 

84 

85 Parameters 

86 --------------- 

87 mag_to_flux : magnitude to flux values 

88 

89 Returns 

90 ----------- 

91 m5 values 

92 time difference dt (cadence) 

93 metric=sqrt(dt)*F5 where F5 is the 5-sigma flux 

94 

95 """ 

96 dt = np.linspace(self.dt_range[0], self.dt_range[1], 100) 

97 m5 = np.linspace(self.mag_range[0], self.mag_range[1], 50) 

98 ida = mag_to_flux['band'] == self.band 

99 fa = interpolate.interp1d( 

100 mag_to_flux[ida]['m5'], mag_to_flux[ida]['flux_e']) 

101 f5 = fa(m5) 

102 F5, DT = np.meshgrid(f5, dt) 

103 M5, DT = np.meshgrid(m5, dt) 

104 metric = np.sqrt(DT) * F5 

105 

106 return M5, DT, metric 

107 

108 def interp(self): 

109 """ 

110 Estimate a grid of interpolated values 

111 in the plane (m5, cadence, metric) 

112 

113 Parameters 

114 --------------- 

115 None 

116 

117 """ 

118 

119 M5_all = [] 

120 DT_all = [] 

121 metric_all = [] 

122 

123 for val in self.mag_to_flux: 

124 M5, DT, metric = self.mesh(val) 

125 M5_all.append(M5) 

126 DT_all.append(DT) 

127 metric_all.append(metric) 

128 

129 sorted_keys = [] 

130 for i in range(len(self.lims)): 

131 sorted_keys.append(np.sort([k for k in self.lims[i].keys()])[::-1]) 

132 figa, axa = plt.subplots() 

133 

134 for kk, lim in enumerate(self.lims): 

135 fmt = {} 

136 ll = [lim[zz][self.band] for zz in sorted_keys[kk]] 

137 cs = axa.contour(M5_all[kk], DT_all[kk], metric_all[kk], ll) 

138 

139 points_values = None 

140 for io, col in enumerate(cs.collections): 

141 if col.get_segments(): 

142 

143 myarray = col.get_segments()[0] 

144 res = np.array(myarray[:, 0], dtype=[('m5', 'f8')]) 

145 res = rf.append_fields(res, 'cadence', myarray[:, 1]) 

146 res = rf.append_fields( 

147 res, 'z', [sorted_keys[kk][io]]*len(res)) 

148 if points_values is None: 

149 points_values = res 

150 else: 

151 points_values = np.concatenate((points_values, res)) 

152 self.points_ref = points_values 

153 

154 plt.close(figa) # do not display 

155 

156 def interp_griddata(self, data): 

157 """ 

158 Estimate metric interpolation for data (m5,cadence) 

159 

160 Parameters 

161 --------------- 

162 data : data where interpolation has to be done (m5,cadence) 

163 

164 Returns 

165 ----------- 

166 griddata interpolation (m5,cadence,metric) 

167 

168 """ 

169 

170 ref_points = self.points_ref 

171 res = interpolate.griddata((ref_points['m5'], ref_points['cadence']), ref_points['z'], ( 

172 data['m5_mean'], data['cadence_mean']), method='cubic') 

173 return res 

174 

175 

176class GenerateFakeObservations: 

177 """ Class to generate Fake observations 

178 

179 Parameters 

180 --------- 

181 config: yaml-like 

182 configuration file (parameter choice: filter, cadence, m5,Nseasons, ...) 

183 list : str,opt 

184 Name of the columns used. 

185 Default : 'observationStartMJD', 'fieldRA', 'fieldDec','filter','fiveSigmaDepth','visitExposureTime','numExposures','visitTime','season' 

186 

187 Returns 

188 --------- 

189 recordarray of observations with the fields: 

190 MJD, Ra, Dec, band,m5,Nexp, ExpTime, Season 

191 """ 

192 

193 def __init__(self, config, 

194 mjdCol='observationStartMJD', RaCol='fieldRA', 

195 DecCol='fieldDec', filterCol='filter', m5Col='fiveSigmaDepth', 

196 exptimeCol='visitExposureTime', nexpCol='numExposures', seasonCol='season'): 

197 

198 self.mjdCol = mjdCol 

199 self.m5Col = m5Col 

200 self.filterCol = filterCol 

201 self.RaCol = RaCol 

202 self.DecCol = DecCol 

203 self.exptimeCol = exptimeCol 

204 self.seasonCol = seasonCol 

205 self.nexpCol = nexpCol 

206 

207 # now make fake obs 

208 self.make_fake(config) 

209 

210 def make_fake(self, config): 

211 """ Generate Fake observations 

212 

213 Parameters 

214 --------- 

215 config: yaml-like 

216 configuration file (parameter choice: filter, cadence, m5,Nseasons, ...) 

217 

218 

219 """ 

220 bands = config['bands'] 

221 cadence = dict(zip(bands, config['Cadence'])) 

222 shift_days = dict( 

223 zip(bands, [config['shift_days']*io for io in range(len(bands))])) 

224 m5 = dict(zip(bands, config['m5'])) 

225 Nvisits = dict(zip(bands, config['Nvisits'])) 

226 Exposure_Time = dict(zip(bands, config['Exposure_Time'])) 

227 inter_season_gap = 300. 

228 

229 Ra = config['Ra'] 

230 Dec = config['Dec'] 

231 rtot = [] 

232 # for season in range(1, config['nseasons']+1): 

233 for il, season in enumerate(config['seasons']): 

234 # mjd_min = config['MJD_min'] + float(season-1)*inter_season_gap 

235 mjd_min = config['MJD_min'][il] 

236 mjd_max = mjd_min+config['season_length'] 

237 

238 for i, band in enumerate(bands): 

239 mjd = np.arange(mjd_min, mjd_max+cadence[band], cadence[band]) 

240 mjd += shift_days[band] 

241 m5_coadded = self.m5_coadd(m5[band], 

242 Nvisits[band], 

243 Exposure_Time[band]) 

244 myarr = np.array(mjd, dtype=[(self.mjdCol, 'f8')]) 

245 myarr = rf.append_fields(myarr, [self.RaCol, self.DecCol, self.filterCol], [ 

246 [Ra]*len(myarr), [Dec]*len(myarr), [band]*len(myarr)]) 

247 myarr = rf.append_fields(myarr, [self.m5Col, self.nexpCol, self.exptimeCol, self.seasonCol], [ 

248 [m5_coadded]*len(myarr), [Nvisits[band]]*len(myarr), [Nvisits[band]*Exposure_Time[band]]*len(myarr), [season]*len(myarr)]) 

249 rtot.append(myarr) 

250 

251 res = np.copy(np.concatenate(rtot)) 

252 res.sort(order=self.mjdCol) 

253 

254 self.Observations = res 

255 

256 def m5_coadd(self, m5, Nvisits, Tvisit): 

257 """ Coadded m5 estimation 

258 

259 Parameters 

260 --------- 

261 m5 : list(float) 

262 list of five-sigma depth values 

263 Nvisits : list(float) 

264 list of the number of visits 

265 Tvisit : list(float) 

266 list of the visit times 

267 

268 Returns 

269 --------- 

270 m5_coadd : list(float) 

271 list of m5 coadded values 

272 

273 """ 

274 m5_coadd = m5+1.25*np.log10(float(Nvisits)*Tvisit/30.) 

275 return m5_coadd 

276 

277 

278class ReferenceData: 

279 """ 

280 class to handle light curve of SN 

281 

282 Parameters 

283 --------------- 

284 Li_files : str 

285 light curve reference file 

286 mag_to_flux_files : str 

287 files of magnitude to flux 

288 band : str 

289 band considered 

290 z : float 

291 redshift considered 

292 """ 

293 

294 def __init__(self, Li_files, mag_to_flux_files, band, z): 

295 

296 self.band = band 

297 self.z = z 

298 self.fluxes = [] 

299 self.mag_to_flux = [] 

300 

301 for val in Li_files: 

302 self.fluxes.append(self.interp_fluxes( 

303 self.band, np.load(val), self.z)) 

304 for val in mag_to_flux_files: 

305 self.mag_to_flux.append( 

306 self.interp_mag(self.band, np.load(val))) 

307 

308 def interp_fluxes(self, band, tab, z): 

309 """ 

310 Flux interpolator 

311 

312 Parameters 

313 --------------- 

314 band : str 

315 band considered 

316 tab : array 

317 reference data with (at least) fields z,band,time,DayMax 

318 z : float 

319 redshift considered 

320 

321 Returns 

322 ----- 

323 list (float) of interpolated fluxes (in e/sec) 

324 """ 

325 lims = {} 

326 idx = (np.abs(tab['z'] - z) < 1.e-5) & (tab['band'] == 'LSST::'+band) 

327 sel = tab[idx] 

328 selc = np.copy(sel) 

329 difftime = (sel['time']-sel['DayMax']) 

330 selc = rf.append_fields(selc, 'deltaT', difftime) 

331 return interpolate.interp1d(selc['deltaT'], selc['flux_e'], bounds_error=False, fill_value=0.) 

332 

333 def interp_mag(self, band, tab): 

334 """ 

335 magnitude (m5) to flux (e/sec) interpolator 

336 

337 Parameters 

338 --------------- 

339 band : str 

340 band considered 

341 tab : array 

342 reference data with (at least) fields band,m5,flux_e, 

343 z : float 

344 redshift considered 

345 

346 Returns 

347 ----- 

348 list (float) of interpolated fluxes (in e/sec) 

349 """ 

350 idx = tab['band'] == band 

351 sel = tab[idx] 

352 return interpolate.interp1d(sel['m5'], sel['flux_e'], bounds_error=False, fill_value=0.)