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

1from builtins import zip 

2from builtins import object 

3import os 

4import copy 

5import numpy 

6from .Bandpass import Bandpass 

7from .Sed import Sed 

8from lsst.sims.photUtils import getImsimFluxNorm 

9 

10__all__ = ["SedList"] 

11 

12class SedList(object): 

13 """ 

14 This class will read in a list of Seds from disk and store them. 

15 

16 It also has the ability to renormalize, redden (according to the 

17 O'Donnell 94, ApJ 422 158 dust model), and redshift the Seds. 

18 

19 As it reads in the Seds, it will keep track of each unique file it reads 

20 in. If two Seds are based on the same file (before normalization, reddening, 

21 etc.), it will refer back to its own memory, rather than reading the 

22 file from disk a second time. 

23 

24 The method loadSedsFromList allows the user to add Seds to the list 

25 after the constructor has been called. 

26 """ 

27 

28 def __init__(self, sedNameList, magNormList, 

29 normalizingBandpass=None, 

30 specMap=None, 

31 fileDir = '', 

32 wavelenMatch = None, 

33 redshiftList = None, 

34 galacticAvList = None, 

35 internalAvList = None, 

36 cosmologicalDimming = True): 

37 

38 """ 

39 @param [in] sedNameList is a list of SED file names. 

40 

41 @param [in] magNormList is a list of magnitude normalizations 

42 (in the normalizingBandpass) for each of the Seds. 

43 

44 @param[in] normalizingBandpass is an instantiation of the Bandpass 

45 class defining the bandpass in which the magNorms from magNormList 

46 are calculated. This defaults to the Bandpass().imsimBandpass(), 

47 which is essentially a delta function at 500 nm. 

48 

49 @param [in] fileDir is the base directory where the Sed files are stored 

50 (defaults to current working directory). 

51 

52 @param [in] specMap is a specMap (defined in sims_utils/../fileMaps.py) 

53 that maps the names in sedNameList to paths of the files relative to 

54 fileDir (defaults to None; a defaultSpecMap targeted at 

55 sims_sed_library is defined in sims_utils) 

56 

57 @param [in] wavelenMatch is an optional numpy array representing 

58 the wavelength grid to which all Seds will be re-mapped. 

59 

60 @param [in] redshiftList is an optional list of redshifts for the Sed 

61 

62 @param [in] internalAvList is an optional list of A(V) due to internal 

63 dust (for spectra of galaxies). 

64 

65 @param [in] galacticAvList is an optional list of A(V) due to 

66 Milky Way Dust. 

67 

68 @param [in] cosmologicalDimming is a boolean indicating whether cosmological 

69 dimming (the extray (1+z)^-1 factor in flux) should be applied to spectra 

70 when they are redshifted (defaults to True) 

71 

72 Note: once wavelenMatch and cosmologicalDimming have been set in 

73 the constructor, they cannot be un-set. 

74 

75 Similarly: if you construct a SedList without a galacticAvList, 

76 internalAvList, or redshiftList, you cannot later add spectra with 

77 whichever of those features were left out. 

78 """ 

79 

80 

81 self._initialized = False 

82 self._spec_map = specMap 

83 self._wavelen_match = copy.deepcopy(wavelenMatch) 

84 self._file_dir = fileDir 

85 self._cosmological_dimming = cosmologicalDimming 

86 

87 self._normalizing_bandpass = normalizingBandpass 

88 

89 self._sed_list = [] 

90 self._redshift_list = None 

91 self._galactic_av_list = None 

92 self._internal_av_list = None 

93 

94 self._a_int = None 

95 self._b_int = None 

96 self._av_int_wavelen = None 

97 

98 self._a_gal = None 

99 self._b_gal = None 

100 self._av_gal_wavelen = None 

101 

102 self.loadSedsFromList(sedNameList, magNormList, 

103 internalAvList = internalAvList, 

104 galacticAvList = galacticAvList, 

105 redshiftList = redshiftList) 

106 

107 

108 def __len__(self): 

109 return len(self._sed_list) 

110 

111 def __getitem__(self, index): 

112 return self._sed_list[index] 

113 

114 def __iter__(self): 

115 for val in self._sed_list: 

116 yield val 

117 

118 

119 # Handy routines for handling Sed/Bandpass routines with sets of dictionaries. 

120 def loadSedsFromList(self, sedNameList, magNormList, \ 

121 internalAvList=None, galacticAvList=None, redshiftList=None): 

122 """ 

123 Load the Seds specified by sedNameList, applying the specified normalization, 

124 extinction, and redshift. 

125 

126 @param [in] sedList is a list of file names containing Seds 

127 

128 @param [in] magNorm is the magnitude normalization 

129 

130 @param [in] internalAvList is an optional list of A(V) due to internal 

131 dust 

132 

133 @param [in] galacticAvList is an optional list of A(V) due to 

134 Milky Way dust 

135 

136 @param [in] redshiftList is an optional list of redshifts for the 

137 input Sed 

138 

139 Seds are read in and stored to this object's internal list of Seds. 

140 

141 Note: if you constructed this SedList object without internalAvList, 

142 you cannot load Seds with internalAvList now. Likewise for galacticAvlist 

143 and redshiftList. 

144 """ 

145 

146 if not self._initialized: 

147 if internalAvList is not None: 

148 self._internal_av_list = copy.deepcopy(list(internalAvList)) 

149 else: 

150 self._internal_av_list = None 

151 

152 if galacticAvList is not None: 

153 self._galactic_av_list = copy.deepcopy(list(galacticAvList)) 

154 else: 

155 self._galactic_av_list = None 

156 

157 if redshiftList is not None: 

158 self._redshift_list = copy.deepcopy(list(redshiftList)) 

159 else: 

160 self._redshift_list = None 

161 

162 else: 

163 if self._internal_av_list is None and internalAvList is not None: 

164 raise RuntimeError("This SedList does not contain internalAvList") 

165 elif self._internal_av_list is not None: 

166 if internalAvList is None: 

167 self._internal_av_list += [None] * len(sedNameList) 

168 else: 

169 self._internal_av_list += list(internalAvList) 

170 

171 if self._galactic_av_list is None and galacticAvList is not None: 

172 raise RuntimeError("This SedList does not contain galacticAvList") 

173 elif self._galactic_av_list is not None: 

174 if galacticAvList is None: 

175 self._galactic_av_list += [None] * len(sedNameList) 

176 else: 

177 self._galactic_av_list += list(galacticAvList) 

178 

179 if self._redshift_list is None and redshiftList is not None: 

180 raise RuntimeError("This SedList does not contain redshiftList") 

181 elif self._redshift_list is not None: 

182 if redshiftList is None: 

183 self._redshift_list += [None] * len(sedNameList) 

184 else: 

185 self._redshift_list += list(redshiftList) 

186 

187 temp_sed_list = [] 

188 for sedName, magNorm in zip(sedNameList, magNormList): 

189 sed = Sed() 

190 

191 if sedName != "None": 

192 if self._spec_map is not None: 

193 sed.readSED_flambda(os.path.join(self._file_dir, self._spec_map[sedName])) 

194 else: 

195 sed.readSED_flambda(os.path.join(self._file_dir, sedName)) 

196 

197 if self._normalizing_bandpass is not None: 

198 fNorm = sed.calcFluxNorm(magNorm, self._normalizing_bandpass) 

199 else: 

200 fNorm = getImsimFluxNorm(sed, magNorm) 

201 

202 sed.multiplyFluxNorm(fNorm) 

203 

204 temp_sed_list.append(sed) 

205 

206 

207 if internalAvList is not None: 

208 self._av_int_wavelen, \ 

209 self._a_int, \ 

210 self._b_int = self.applyAv(temp_sed_list, internalAvList, 

211 self._av_int_wavelen, self._a_int, self._b_int) 

212 

213 if redshiftList is not None: 

214 self.applyRedshift(temp_sed_list, redshiftList) 

215 

216 if self._wavelen_match is not None: 

217 for sedObj in temp_sed_list: 

218 if sedObj.wavelen is not None: 

219 sedObj.resampleSED(wavelen_match=self._wavelen_match) 

220 

221 if galacticAvList is not None: 

222 self._av_gal_wavelen, \ 

223 self._a_gal, \ 

224 self._b_gal = self.applyAv(temp_sed_list, galacticAvList, 

225 self._av_gal_wavelen, self._a_gal, self._b_gal) 

226 

227 self._sed_list += temp_sed_list 

228 

229 self._initialized = True 

230 

231 

232 

233 def applyAv(self, sedList, avList, dustWavelen, aCoeffs, bCoeffs): 

234 """ 

235 Take the array of Sed objects sedList and apply extinction due to dust. 

236 

237 This method makes the necessary changes to the Seds in SedList in situ. 

238 It returns the wavelength grid and corresponding dust coefficients so that 

239 they an be reused on Seds with identical wavelength grids. 

240 

241 @param [in] sedList is a list of Sed objects 

242 

243 @param [in] avList is a list of Av extinction values internal to each object 

244 

245 @param [in] dustWavelen is the wavelength grid corresponding to the 

246 dust model coefficients. If this differs from the wavelength grid 

247 of any of the Seds in sedList, the dust model coefficients will be 

248 re-generated. 

249 

250 @param [in] aCoeffs are the 'a' dust model coefficients (see O'Donnell 1994 

251 ApJ 422 158) 

252 

253 @param [in] bCoeffs are the 'b' dust model coefficients from O'Donnell. 

254 

255 @param [out] dustWavelen as generated/used by this method 

256 

257 @param [out] aCoeffs as generated/used by this method 

258 

259 @param [out] bCoeffs as generated/used by this method 

260 

261 aCoeffs and bCoeffs are re-generated as needed 

262 """ 

263 

264 for sedobj, av in zip(sedList, avList): 

265 if sedobj.wavelen is not None and av is not None: 

266 #setupCCM_ab only depends on the wavelen array 

267 #because this is supposed to be the same for every 

268 #SED object in sedList, it is only called once for 

269 #each invocation of applyAv 

270 

271 if dustWavelen is None or len(sedobj.wavelen)!=len(dustWavelen) \ 

272 or (sedobj.wavelen!=dustWavelen).any(): 

273 aCoeffs, bCoeffs = sedobj.setupCCM_ab() 

274 dustWavelen = sedobj.wavelen 

275 

276 sedobj.addDust(aCoeffs, bCoeffs, A_v=av) 

277 

278 

279 return dustWavelen, aCoeffs, bCoeffs 

280 

281 

282 def applyRedshift(self, sedList, redshiftList): 

283 """ 

284 Take the array of SED objects sedList and apply the arrays of extinction and redshift 

285 (internalAV and redshift) 

286 

287 This method does not return anything. It makes the necessary changes 

288 to the Seds in SedList in situ. 

289 

290 @param [in] sedList is a list of Sed objects 

291 

292 @param [in] redshiftList is a list of redshift values 

293 

294 This method will redshift each Sed object in sedList 

295 """ 

296 

297 if redshiftList is None: 

298 return 

299 

300 for sedobj, redshift in zip(sedList, redshiftList): 

301 if sedobj.wavelen is not None and redshift is not None: 

302 sedobj.redshiftSED(redshift, dimming=self._cosmological_dimming) 

303 sedobj.name = sedobj.name + '_Z' + '%.2f' %(redshift) 

304 

305 

306 def flush(self): 

307 """ 

308 Delete all SEDs stored in this SedList. 

309 """ 

310 self._initialized = False 

311 self._sed_list = [] 

312 self._internal_av_list = None 

313 self._galactic_av_list = None 

314 self._redshift_list = None 

315 

316 

317 @property 

318 def cosmologicalDimming(self): 

319 """ 

320 Boolean determining whether cosmological dimming (the extra 

321 (1+z)^-1 factor in flux) is applied to Seds when they are 

322 redshifte by this SedList. 

323 """ 

324 return self._cosmological_dimming 

325 

326 

327 @property 

328 def wavelenMatch(self): 

329 """ 

330 Wavelength grid against which to match Seds stored in this 

331 SedList. 

332 """ 

333 return self._wavelen_match 

334 

335 

336 @property 

337 def redshiftList(self): 

338 """ 

339 List of redshifts applied to the Seds stored in this 

340 SedList. 

341 """ 

342 return self._redshift_list 

343 

344 

345 @property 

346 def internalAvList(self): 

347 """ 

348 A(V) due to internal dust applied to the Seds stored in 

349 this SedList. 

350 """ 

351 return self._internal_av_list 

352 

353 

354 @property 

355 def galacticAvList(self): 

356 """ 

357 List of A(V) due to Milky Way dust applied to the Seds 

358 stored in this SedList 

359 """ 

360 return self._galactic_av_list