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 __future__ import print_function 

2from builtins import range 

3import os 

4import numpy as np 

5 

6import lsst.utils 

7from lsst.sims.photUtils import Sed 

8from lsst.sims.catUtils.matchSED.matchUtils import matchGalaxy 

9from lsst.sims.photUtils import BandpassDict 

10from lsst.sims.catUtils.dust import EBVbase as ebv 

11 

12__all__ = ["selectGalaxySED"] 

13 

14class selectGalaxySED(matchGalaxy): 

15 

16 """ 

17 This class provides methods to match galaxy catalog magnitudes to an SED. 

18 """ 

19 

20 def matchToRestFrame(self, sedList, catMags, mag_error = None, bandpassDict = None, makeCopy = False): 

21 

22 """ 

23 This will find the closest match to the magnitudes of a galaxy catalog if those magnitudes are in 

24 the rest frame. Objects without magnitudes in at least two adjacent bandpasses will return as none 

25 and print out a message. 

26 

27 @param [in] sedList is the set of spectral objects from the models SEDs provided by loadBC03 

28 or other custom loader routine. 

29 

30 @param [in] catMags is an array of the magnitudes of catalog objects to be matched with a model SED. 

31 It should be organized so that there is one object's magnitudes along each row. 

32 

33 @param [in] mag_error are provided error values for magnitudes in objectMags. If none provided 

34 then this defaults to 1.0. This should be an array of the same size as catMags. 

35 

36 @param [in] bandpassDict is an OrderedDict of bandpass objects with which to calculate magnitudes.  

37 If left equal to None it will by default load the SDSS [u,g,r,i,z] bandpasses. 

38 

39 @param [in] makeCopy indicates whether or not to operate on copies of the SED objects in sedList 

40 since this method will change the wavelength grid. 

41 

42 @param [out] sedMatches is a list with the name of a model SED that matches most closely to each 

43 object in the catalog. 

44 

45 @param [out] magNormMatches are the magnitude normalizations for the given magnitudes and 

46 matched SED. 

47 

48 @param [out] matchErrors contains the Mean Squared Error between the colors of each object and  

49 the colors of the matched SED. 

50 """ 

51 

52 #Set up photometry to calculate model Mags 

53 if bandpassDict is None: 

54 galPhot = BandpassDict.loadTotalBandpassesFromFiles(['u','g','r','i','z'], 

55 bandpassDir = os.path.join(lsst.utils.getPackageDir('throughputs'),'sdss'), 

56 bandpassRoot = 'sdss_') 

57 else: 

58 galPhot = bandpassDict 

59 

60 modelColors = [] 

61 sedMatches = [] 

62 magNormMatches = [] 

63 

64 #Find the colors for all model SEDs 

65 modelColors = self.calcBasicColors(sedList, galPhot, makeCopy = makeCopy) 

66 modelColors = np.transpose(modelColors) 

67 

68 #Match the catalog colors to models 

69 numCatMags = len(catMags) 

70 numOn = 0 

71 notMatched = 0 

72 matchColors = [] 

73 matchErrors = [] 

74 

75 for filtNum in range(0, len(galPhot)-1): 

76 matchColors.append(np.transpose(catMags)[filtNum] - np.transpose(catMags)[filtNum+1]) 

77 

78 matchColors = np.transpose(matchColors) 

79 

80 for catObject in matchColors: 

81 #This is done to handle objects with incomplete magnitude data 

82 colorRange = np.arange(0, len(galPhot)-1) 

83 filtNums = np.arange(0, len(galPhot)) 

84 if np.isnan(np.amin(catObject))==True: 

85 colorRange = np.where(np.isnan(catObject)==False)[0] 

86 filtNums = np.unique([colorRange, colorRange+1]) #To pick out right filters in calcMagNorm 

87 if len(colorRange) == 0: 

88 print('Could not match object #%i. No magnitudes for two adjacent bandpasses.' % (numOn)) 

89 notMatched += 1 

90 sedMatches.append(None) 

91 magNormMatches.append(None) 

92 matchErrors.append(None) 

93 else: 

94 distanceArray = np.zeros(len(sedList)) 

95 for colorNum in colorRange: 

96 distanceArray += np.power((modelColors[colorNum] - catObject[colorNum]),2) 

97 matchedSEDNum = np.nanargmin(distanceArray) 

98 sedMatches.append(sedList[matchedSEDNum].name) 

99 magNorm = self.calcMagNorm(np.array(catMags[numOn]), sedList[matchedSEDNum], 

100 galPhot, mag_error = mag_error, filtRange = filtNums) 

101 magNormMatches.append(magNorm) 

102 matchErrors.append(distanceArray[matchedSEDNum]/len(colorRange)) 

103 numOn += 1 

104 if numOn % 10000 == 0: 

105 print('Matched %i of %i catalog objects to SEDs' % (numOn-notMatched, numCatMags)) 

106 

107 print('Done Matching. Matched %i of %i catalog objects to SEDs' % (numCatMags-notMatched, numCatMags)) 

108 if notMatched > 0: 

109 print('%i objects did not get matched' % (notMatched)) 

110 

111 return sedMatches, magNormMatches, matchErrors 

112 

113 def matchToObserved(self, sedList, catMags, catRedshifts, catRA = None, catDec = None, 

114 mag_error = None, bandpassDict = None, dzAcc = 2, reddening = True, 

115 extCoeffs = (4.239, 3.303, 2.285, 1.698, 1.263)): 

116 

117 """ 

118 This will find the closest match to the magnitudes of a galaxy catalog if those magnitudes are in 

119 the observed frame and can correct for reddening from within the milky way as well if needed. 

120 In order to make things faster it first calculates colors for all model SEDs at redshifts between 

121 the minimum and maximum redshifts of the catalog objects provided with a grid spacing in redshift 

122 defined by the parameter dzAcc. Objects without magnitudes in at least two adjacent bandpasses will 

123 return as none and print out a message. 

124 

125 @param [in] sedList is the set of spectral objects from the models SEDs provided by loadBC03 

126 or other custom loader routine. 

127 

128 @param [in] catMags is an array of the magnitudes of catalog objects to be matched with a model SED. 

129 It should be organized so that there is one object's magnitudes along each row. 

130 

131 @param [in] catRedshifts is an array of the redshifts of each catalog object. 

132 

133 @param [in] catRA is an array of the RA positions for each catalog object. 

134 

135 @param [in] catDec is an array of the Dec position for each catalog object. 

136 

137 @param [in] mag_error are provided error values for magnitudes in objectMags. If none provided 

138 then this defaults to 1.0. This should be an array of the same size as catMags. 

139 

140 @param [in] bandpassDict is a BandpassDict with which to calculate magnitudes. 

141 If left equal to None it will by default load the SDSS [u,g,r,i,z] bandpasses and therefore agree with 

142 default extCoeffs. 

143 

144 @param [in] dzAcc is the number of decimal places you want to use when building the redshift grid. 

145 For example, dzAcc = 2 will create a grid between the minimum and maximum redshifts with colors 

146 calculated at every 0.01 change in redshift. 

147 

148 @param [in] reddening is a boolean that determines whether to correct catalog magnitudes for 

149 dust in the milky way. By default, it is True. 

150 If true, this uses calculateEBV from EBV.py to find an EBV value for the object's 

151 ra and dec coordinates and then uses the coefficients provided by extCoeffs which should come 

152 from Schlafly and Finkbeiner (2011) for the correct filters and in the same order as provided 

153 in bandpassDict. 

154 If false, this means it will not run the dereddening procedure. 

155 

156 @param [in] extCoeffs are the Schlafly and Finkbeiner (2011) (ApJ, 737, 103) coefficients for the 

157 given filters from bandpassDict and need to be in the same order as bandpassDict. The default given 

158 are the SDSS [u,g,r,i,z] values. 

159 

160 @param [out] sedMatches is a list with the name of a model SED that matches most closely to each 

161 object in the catalog. 

162 

163 @param [out] magNormMatches are the magnitude normalizations for the given magnitudes and 

164 matched SED. 

165 

166 @param [out] matchErrors contains the Mean Squared Error between the colors of each object and  

167 the colors of the matched SED. 

168 """ 

169 

170 #Set up photometry to calculate model Mags 

171 if bandpassDict is None: 

172 galPhot = BandpassDict.loadTotalBandpassesFromFiles(['u','g','r','i','z'], 

173 bandpassDir = os.path.join(lsst.utils.getPackageDir('throughputs'),'sdss'), 

174 bandpassRoot = 'sdss_') 

175 else: 

176 galPhot = bandpassDict 

177 

178 #Calculate ebv from ra, dec coordinates if needed 

179 if reddening == True: 

180 #Check that catRA and catDec are included 

181 if catRA is None or catDec is None: 

182 raise RuntimeError("Reddening is True, but catRA and catDec are not included.") 

183 calcEBV = ebv() 

184 raDec = np.array((catRA,catDec)) 

185 #If only matching one object need to reshape for calculateEbv 

186 if len(raDec.shape) == 1: 

187 raDec = raDec.reshape((2,1)) 

188 ebvVals = calcEBV.calculateEbv(equatorialCoordinates = raDec) 

189 objMags = self.deReddenMags(ebvVals, catMags, extCoeffs) 

190 else: 

191 objMags = catMags 

192 

193 minRedshift = np.round(np.min(catRedshifts), dzAcc) 

194 maxRedshift = np.round(np.max(catRedshifts), dzAcc) 

195 dz = np.power(10., (-1*dzAcc)) 

196 

197 redshiftRange = np.round(np.arange(minRedshift - dz, maxRedshift + (2*dz), dz), dzAcc) 

198 numRedshifted = 0 

199 sedMatches = [None] * len(catRedshifts) 

200 magNormMatches = [None] * len(catRedshifts) 

201 matchErrors = [None] * len(catRedshifts) 

202 redshiftIndex = np.argsort(catRedshifts) 

203 

204 numOn = 0 

205 notMatched = 0 

206 lastRedshift = -100 

207 print('Starting Matching. Arranged by redshift value.') 

208 for redshift in redshiftRange: 

209 

210 if numRedshifted % 10 == 0: 

211 print('%i out of %i redshifts gone through' % (numRedshifted, len(redshiftRange))) 

212 numRedshifted += 1 

213 

214 colorSet = [] 

215 for galSpec in sedList: 

216 sedColors = [] 

217 fileSED = Sed() 

218 fileSED.setSED(wavelen = galSpec.wavelen, flambda = galSpec.flambda) 

219 fileSED.redshiftSED(redshift) 

220 sedColors = self.calcBasicColors([fileSED], galPhot, makeCopy = True) 

221 colorSet.append(sedColors) 

222 colorSet = np.transpose(colorSet) 

223 for currentIndex in redshiftIndex[numOn:]: 

224 matchMags = objMags[currentIndex] 

225 if lastRedshift < np.round(catRedshifts[currentIndex],dzAcc) <= redshift: 

226 colorRange = np.arange(0, len(galPhot)-1) 

227 matchColors = [] 

228 for colorNum in colorRange: 

229 matchColors.append(matchMags[colorNum] - matchMags[colorNum+1]) 

230 #This is done to handle objects with incomplete magnitude data 

231 filtNums = np.arange(0, len(galPhot)) 

232 if np.isnan(np.amin(matchColors))==True: 

233 colorRange = np.where(np.isnan(matchColors)==False)[0] 

234 filtNums = np.unique([colorRange, colorRange+1]) #Pick right filters in calcMagNorm 

235 if len(colorRange) == 0: 

236 print('Could not match object #%i. No magnitudes for two adjacent bandpasses.' \ 

237 % (currentIndex)) 

238 notMatched += 1 

239 #Don't need to assign 'None' here in result array, b/c 'None' is default value 

240 else: 

241 distanceArray = [np.zeros(len(sedList))] 

242 for colorNum in colorRange: 

243 distanceArray += np.power((colorSet[colorNum] - matchColors[colorNum]),2) 

244 matchedSEDNum = np.nanargmin(distanceArray) 

245 sedMatches[currentIndex] = sedList[matchedSEDNum].name 

246 magNormVal = self.calcMagNorm(np.array(matchMags), sedList[matchedSEDNum], 

247 galPhot, mag_error = mag_error, 

248 redshift = catRedshifts[currentIndex], 

249 filtRange = filtNums) 

250 magNormMatches[currentIndex] = magNormVal 

251 matchErrors[currentIndex] = (distanceArray[0,matchedSEDNum]/len(colorRange)) 

252 numOn += 1 

253 else: 

254 break 

255 lastRedshift = redshift 

256 

257 print('Done Matching. Matched %i of %i catalog objects to SEDs' % (len(catMags)-notMatched, 

258 len(catMags))) 

259 if notMatched > 0: 

260 print('%i objects did not get matched.' % (notMatched)) 

261 

262 return sedMatches, magNormMatches, matchErrors