Coverage for python/lsst/sims/catUtils/matchSED/matchUtils.py : 9%

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# -*- coding: utf-8 -*-
2"""
3Created on Wed Feb 25 14:07:03 2015
5@author: Bryce Kalmbach
6"""
7from __future__ import print_function
8from builtins import zip
9from builtins import str
10from builtins import range
11from builtins import object
12import numpy as np
13import os
14import re
15import lsst.utils
16from lsst.sims.photUtils import Sed
17from lsst.sims.photUtils import Bandpass
18from lsst.sims.utils import SpecMap
20__all__ = ["matchBase", "matchStar", "matchGalaxy"]
22class matchBase(object):
24 """
25 This class is designed to provide methods that will be useful to both selectStarSED and selectGalaxySED.
26 """
28 def calcMagNorm(self, objectMags, sedObj, bandpassDict, mag_error = None,
29 redshift = None, filtRange = None):
31 """
32 This will find the magNorm value that gives the closest match to the magnitudes of the object
33 using the matched SED. Uses scipy.optimize.leastsq to find the values of fluxNorm that minimizes
34 the function: ((flux_obs - (fluxNorm*flux_model))/flux_error)**2.
36 @param [in] objectMags are the magnitude values for the object with extinction matching that of
37 the SED object. In the normal case using the selectSED routines above it will be dereddened mags.
39 @param [in] sedObj is an Sed class instance that is set with the wavelength and flux of the
40 matched SED
42 @param [in] bandpassDict is a BandpassDict class instance with the Bandpasses set to those
43 for the magnitudes given for the catalog object
45 @param [in] mag_error are provided error values for magnitudes in objectMags. If none provided
46 then this defaults to 1.0. This should be an array of the same length as objectMags.
48 @param [in] redshift is the redshift of the object if the magnitude is observed
50 @param [in] filtRange is a selected range of filters specified by their indices in the bandpassList
51 to match up against. Used when missing data in some magnitude bands.
53 @param [out] bestMagNorm is the magnitude normalization for the given magnitudes and SED
54 """
56 import scipy.optimize as opt
58 sedTest = Sed()
59 sedTest.setSED(sedObj.wavelen, flambda = sedObj.flambda)
60 if redshift is not None:
61 sedTest.redshiftSED(redshift)
62 imSimBand = Bandpass()
63 imSimBand.imsimBandpass()
64 zp = -2.5*np.log10(3631) #Note using default AB zeropoint
65 flux_obs = np.power(10,(objectMags + zp)/(-2.5))
66 sedTest.resampleSED(wavelen_match=bandpassDict.wavelenMatch)
67 sedTest.flambdaTofnu()
68 flux_model = sedTest.manyFluxCalc(bandpassDict.phiArray, bandpassDict.wavelenStep)
69 if filtRange is not None:
70 flux_obs = flux_obs[filtRange]
71 flux_model = flux_model[filtRange]
72 if mag_error is None:
73 flux_error = np.ones(len(flux_obs))
74 else:
75 flux_error = np.abs(flux_obs*(np.log(10)/(-2.5))*mag_error)
76 bestFluxNorm = opt.leastsq(lambda x: ((flux_obs - (x*flux_model))/flux_error), 1.0)[0][0]
77 sedTest.multiplyFluxNorm(bestFluxNorm)
78 bestMagNorm = sedTest.calcMag(imSimBand)
79 return bestMagNorm
81 def calcBasicColors(self, sedList, bandpassDict, makeCopy = False):
83 """
84 This will calculate a set of colors from a list of SED objects when there is no need to redshift
85 the SEDs.
87 @param [in] sedList is the set of spectral objects from the models SEDs provided by loaders in
88 rgStar or rgGalaxy. NOTE: Since this uses photometryBase.manyMagCalc_list the SED objects
89 will be changed.
91 @param [in] bandpassDict is a BandpassDict class instance with the Bandpasses set to those
92 for the magnitudes given for the catalog object
94 @param [in] makeCopy indicates whether or not to operate on copies of the SED objects in sedList
95 since this method will change the wavelength grid.
97 @param [out] modelColors is the set of colors in the Bandpasses provided for the given sedList.
98 """
100 modelColors = []
102 for specObj in sedList:
103 if makeCopy==True:
104 fileSED = Sed()
105 fileSED.setSED(wavelen = specObj.wavelen, flambda = specObj.flambda)
106 sEDMags = bandpassDict.magListForSed(fileSED)
107 else:
108 sEDMags = bandpassDict.magListForSed(specObj)
109 colorInfo = []
110 for filtNum in range(0, len(bandpassDict)-1):
111 colorInfo.append(sEDMags[filtNum] - sEDMags[filtNum+1])
112 modelColors.append(colorInfo)
114 return modelColors
116 def deReddenMags(self, ebvVals, catMags, extCoeffs):
118 """
119 This will correct for extinction effects in a set of catalog Magnitudes.
121 @param [in] ebvVals is a list of ebv Values from calculateEBV in ebv.py or given by user that
122 correspond to the same set of objects as the set of magnitudes.
124 @param [in] catMags is an array of the magnitudes of the catalog objects.
126 @param [in] extCoeffs is a list of the coefficients which should come
127 from Schlafly and Finkbeiner (2011) (ApJ, 737, 103) for the same filters and in the same order
128 as the catalog mags.
130 @param [out] deRedMags is the array of corrected magnitudes.
131 """
133 deRedMags = catMags - np.outer(np.array(ebvVals), np.array(extCoeffs))
135 return deRedMags
137class matchStar(matchBase):
139 """
140 This class provides loading routines for the star SEDs currently in sims_sed_library.
141 To load one's own SED library, the user can subclass this and add their own loader following
142 the format of those included here.
143 """
145 def __init__(self, sEDDir=None, kuruczDir=None, mltDir=None, wdDir=None):
147 """
148 @param [in] sEDDir is a place to specify a different path to a directory that follows the same
149 directory structure as SIMS_SED_LIBRARY. If not specified, this will
150 attempt to default to the SIMS_SED_LIBRARY.
152 @param [in] kuruczDir is a place to specify a different path to kurucz SED files than the
153 files in the LSST sims_sed_library. If set to None it will default to the LSST library.
154 Will probably be most useful for those who want to use loadGalfast without downloading the
155 entire LSST sims_sed_library which contains much more than just the star SEDs.
157 @param [in] mltDir is the same as kuruczPath except that it specifies a directory for the
158 mlt SEDs
160 @param [in] wdDir is the same as the previous two except that it specifies a path to an
161 alternate white dwarf SED directory.
162 """
163 #Use SpecMap to pull the directory locations
164 specMap = SpecMap()
165 self.specMapDict = {}
166 specFileStart = ['kp', 'burrows', 'bergeron'] #The beginning of filenames of different SED types
167 specFileTypes = ['kurucz', 'mlt', 'wd']
168 for specStart, specKey in zip(specFileStart, specFileTypes):
169 for key, val in sorted(specMap.subdir_map.items()):
170 if re.match(key, specStart):
171 self.specMapDict[specKey] = str(val)
173 if sEDDir is None:
174 try:
175 self.sEDDir = lsst.utils.getPackageDir('sims_sed_library')
176 except:
177 self.sEDDir = None
178 else:
179 self.sEDDir = sEDDir
181 self.kuruczDir = kuruczDir
182 self.mltDir = mltDir
183 self.wdDir = wdDir
186 def loadKuruczSEDs(self, subset = None):
187 """
188 By default will load all seds in kurucz directory. The user can also define a subset of
189 what's in the directory and load only those SEDs instead. Will skip over extraneous
190 files in sed folder.
192 @param [in] subset is the list of the subset of files wanted if one doesn't want all files
193 in the kurucz directory.
195 @param [out] sedList is the set of model SED spectra objects to be passed onto the matching
196 routines.
197 """
199 if self.kuruczDir is None:
200 try:
201 self.kuruczDir = str(self.sEDDir + '/' +
202 self.specMapDict['kurucz'] + '/')
203 except:
204 raise ValueError(str('self.kuruczDir is None. ' +
205 'Add path to kurucz directory.'))
207 files = []
209 if subset is None:
210 for fileName in os.listdir(self.kuruczDir):
211 files.append(fileName)
212 else:
213 for fileName in subset:
214 files.append(fileName)
216 numFiles = len(files)
217 numOn = 0
219 sedList = []
221 for fileName in files:
222 if numOn % 100 == 0:
223 print('Loading %i of %i: Kurucz SEDs' % (numOn, numFiles))
225 try:
226 spec = Sed()
227 spec.readSED_flambda(str(self.kuruczDir + '/' + fileName))
229 logZTimesTen, temp, gravity, fineTemp = [x.split(".")[0] for x in fileName.split("_")]
231 if logZTimesTen[1] == 'm':
232 spec.logZ = -1.0 * float(logZTimesTen[2:]) * 0.1
233 else:
234 spec.logZ = float(logZTimesTen[2:]) * 0.1
236 spec.logg = float(gravity[1:]) * 0.1
237 spec.temp = float(fineTemp)
238 spec.name = fileName
240 except:
241 continue
243 sedList.append(spec)
245 numOn += 1
247 return sedList
249 def loadmltSEDs(self, subset = None):
251 """
252 By default will load all seds in mlt directory. The user can also define a subset of
253 what's in the directory and load only those SEDs instead. Will skip over extraneous
254 files in sed folder.
256 @param [in] subset is the list of the subset of files wanted if one doesn't want all files
257 in the mlt directory.
259 @param [out] sedList is the set of model SED spectra objects to be passed onto the matching
260 routines.
261 """
263 if self.mltDir is None:
264 try:
265 self.mltDir = str(self.sEDDir + '/' +
266 self.specMapDict['mlt'] + '/')
267 except:
268 raise ValueError(str('self.mltDir is None. ' +
269 'Add path to mlt directory.'))
271 files = []
273 if subset is None:
274 for fileName in os.listdir(self.mltDir):
275 files.append(fileName)
276 else:
277 for fileName in subset:
278 files.append(fileName)
280 numFiles = len(files)
281 numOn = 0
283 sedList = []
285 for fileName in files:
286 if numOn % 100 == 0:
287 print('Loading %i of %i: MLT SEDs' % (numOn, numFiles))
289 try:
290 spec = Sed()
291 spec.readSED_flambda(str(self.mltDir + '/' + fileName))
292 spec.name = fileName
294 except:
295 continue
297 sedList.append(spec)
299 numOn += 1
301 return sedList
304 def loadwdSEDs(self, subset = None):
306 """
307 By default will load all seds in wd directory. The user can also define a subset of
308 what's in the directory and load only those SEDs instead. Will skip over extraneous
309 files in sed folder.
311 @param [in] subset is the list of the subset of files wanted if one doesn't want all files
312 in the kurucz directory.
314 @param [out] sedListH is the set of model SED spectra objects for Hydrogen WDs to be passed onto
315 the matching routines.
317 @param [out] sedListHE is the set of model SED spectra objects for Helium WDs to be passed onto
318 the matching routines.
319 """
321 if self.wdDir is None:
322 try:
323 self.wdDir = str(self.sEDDir + '/' +
324 self.specMapDict['wd'] + '/')
325 except:
326 raise ValueError(str('self.wdDir is None. ' +
327 'Add path to wddirectory.'))
330 files = []
332 if subset is None:
333 for fileName in os.listdir(self.wdDir):
334 files.append(fileName)
335 else:
336 for fileName in subset:
337 files.append(fileName)
339 numFiles = len(files)
340 numOn = 0
342 sedListH = []
343 sedListHE = []
345 for fileName in files:
346 if numOn % 100 == 0:
347 print('Loading %i of %i: WD SEDs' % (numOn, numFiles))
349 try:
350 spec = Sed()
351 spec.readSED_flambda(str(self.wdDir + '/' + fileName))
352 spec.name = fileName
353 if fileName.split("_")[1] == 'He':
354 sedListHE.append(spec)
355 else:
356 sedListH.append(spec)
358 except:
359 continue
361 numOn += 1
363 return sedListH, sedListHE
365class matchGalaxy(matchBase):
367 """
368 This class provides loading routines for the galaxy SEDs currently in sims_sed_library.
369 To load one's own SED library, the user can subclass this and add their own loader following
370 the format of those included here.
371 """
373 def __init__(self, galDir = None):
375 """
376 @param [in] galDir is the directory where the galaxy SEDs are stored
377 """
378 if galDir is None:
379 # Use SpecMap to pull in directory's location in LSST Stack
380 specMap = SpecMap()
381 specFileStart = 'Exp' #Start of sample BC03 name in sims_sed_library
382 for key, val in sorted(specMap.subdir_map.items()):
383 if re.match(key, specFileStart):
384 galSpecDir = str(val)
385 self.galDir = str(lsst.utils.getPackageDir('sims_sed_library') + '/' + galSpecDir)
386 else:
387 self.galDir = galDir
390 def loadBC03(self, subset = None):
392 """
393 This loads the Bruzual and Charlot SEDs that are currently in the SIMS_SED_LIBRARY.
394 If the user wants to use different SEDs another loading method can be created and used in place
395 of this.
397 @param [in] subset is the list of the subset of files in the galDir that the user
398 can specify if using all the SEDs in the directory is not desired.
400 @param [out] sedList is the set of model SED spectra objects to be passed onto the matching routines.
401 """
403 if self.galDir is None:
404 raise ValueError('self.galDir is None. Add path to galaxy directory.')
406 files = []
408 if subset is None:
409 for fileName in os.listdir(self.galDir):
410 files.append(fileName)
411 else:
412 for fileName in subset:
413 files.append(fileName)
415 numFiles = len(files)
416 numOn = 0
418 sedList = []
420 for fileName in files:
421 if numOn % 100 == 0:
422 print('Loading %i of %i: BC Galaxy SEDs' % (numOn, numFiles))
424 try:
425 spec = Sed()
426 spec.readSED_flambda(str(self.galDir + '/' + fileName))
427 spec.name = fileName
428 fileNameAsList = fileName.split('.')
429 spec.type = fileNameAsList[0]
430 spec.age = float(fileNameAsList[1])
431 metallicity = fileNameAsList[2].split('Z')[0]
432 #Final form is z/zSun
433 spec.metallicity = float(metallicity) * (10 ** ((len(metallicity)-1)*-1))
435 except:
436 continue
438 sedList.append(spec)
440 numOn += 1
442 return sedList