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

1# This file is part of obs_lsst. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21 

22__all__ = ( 

23 "LSSTCAM_FILTER_DEFINITIONS", 

24 "LATISS_FILTER_DEFINITIONS", 

25 "LSSTCAM_IMSIM_FILTER_DEFINITIONS", 

26 "TS3_FILTER_DEFINITIONS", 

27 "TS8_FILTER_DEFINITIONS", 

28 "COMCAM_FILTER_DEFINITIONS", 

29) 

30 

31import re 

32from lsst.obs.base import FilterDefinition, FilterDefinitionCollection 

33from .translators.lsst import FILTER_DELIMITER 

34 

35 

36def addFilter(filter_dict, band, physical_filter, lambdaEff=0.0): 

37 """Define a filter in filter_dict, to be converted to a Filter later""" 

38 

39 if band not in filter_dict: 

40 filter_dict[band] = dict(physical_filter=physical_filter, 

41 lambdaEff=lambdaEff, alias=[]) 

42 else: 

43 assert filter_dict[band]["lambdaEff"] == lambdaEff 

44 

45 filter_dict[band]["alias"].append(physical_filter) 

46 

47 

48# The LSST Filters from L. Jones 05/14/2020 - "Edges" = 5% of peak throughput 

49# See https://github.com/rhiannonlynne/notebooks/blob/master/Filter%20Characteristics.ipynb # noqa: W505 

50# 

51# N.b. DM-26623 requests that these physical names be updated once 

52# the camera team has decided upon the final values (CAP-617) 

53 

54LsstCamFiltersBaseline = FilterDefinitionCollection( 

55 FilterDefinition(physical_filter="NONE", band="NONE", 

56 lambdaEff=0.0, 

57 alias={"no_filter", "OPEN"}), 

58 FilterDefinition(physical_filter="u", band="u", 

59 lambdaEff=368.48, lambdaMin=320.00, lambdaMax=408.60), 

60 FilterDefinition(physical_filter="g", band="g", 

61 lambdaEff=480.20, lambdaMin=386.40, lambdaMax=567.00), 

62 FilterDefinition(physical_filter="r", band="r", 

63 lambdaEff=623.12, lambdaMin=537.00, lambdaMax=706.00), 

64 FilterDefinition(physical_filter="i", band="i", 

65 lambdaEff=754.17, lambdaMin=676.00, lambdaMax=833.00), 

66 FilterDefinition(physical_filter="z", band="z", 

67 lambdaEff=869.05, lambdaMin=803.00, lambdaMax=938.60), 

68 FilterDefinition(physical_filter="y", band="y", 

69 lambdaEff=973.64, lambdaMin=908.40, lambdaMax=1099.00), 

70) 

71 

72# 

73# Define the filters present in the BOT. 

74# According to Tony Johnson the possible physical filters are 

75# ColorFWheel [SDSSu,SDSSg,SDSSr,SDSSi,SDSSz,SDSSY, 

76# 480nm,650nm,750nm,870nm,950nm,970nm] 

77# SpotProjFWheel [grid,spot,empty3,empty4,empty5,empty6] 

78# NeutralFWheel [ND_OD1.0,ND_OD0.5,ND_OD0.3,empty,ND_OD2.0,ND_OD0.7] 

79# where: 

80# ColorFWheel and SpotProjFWheel are mutually exclusive and 

81# both appear in FILTER, 

82# NeutralFWheel appears in FILTER2 

83# 

84# Experimentally we also see FILTER2 values of: 

85# ['ND_OD0.01', 'ND_OD0.05', 'ND_OD0.4', 'ND_OD3.0', 'ND_OD4.0'] 

86# 

87# The band names are not yet defined, so I'm going to invent them 

88 

89 

90BOTFilters_dict = {} 

91for physical_filter in [ 

92 "empty", 

93 "SDSSu", 

94 "SDSSg", 

95 "SDSSr", 

96 "SDSSi", 

97 "SDSSz", 

98 "SDSSY", 

99 "480nm", 

100 "650nm", 

101 "750nm", 

102 "870nm", 

103 "950nm", 

104 "970nm", 

105 "grid", 

106 "spot", 

107 "empty3", 

108 "empty4", 

109 "empty5", 

110 "empty6", 

111]: 

112 mat = re.search(r"^SDSS(.)$", physical_filter) 

113 if mat: 

114 band = mat.group(1).lower() 

115 

116 lsstCamFilter = [f for f in LsstCamFiltersBaseline if f.band == band][0] 

117 lambdaEff = lsstCamFilter.lambdaEff 

118 else: 

119 if re.search(r"^empty[3-6]$", physical_filter): 

120 band = "empty" 

121 else: 

122 band = physical_filter 

123 lambdaEff = 0.0 

124 

125 addFilter(BOTFilters_dict, band, physical_filter, lambdaEff=lambdaEff) 

126 

127 ndFilters = ["empty", "ND_OD0.1", "ND_OD0.3", "ND_OD0.5", "ND_OD0.7", "ND_OD1.0", "ND_OD2.0"] 

128 # We found these additional filters in BOT data files: 

129 ndFilters += ['ND_OD0.01', 'ND_OD0.05', 'ND_OD0.4', 'ND_OD3.0', 'ND_OD4.0'] 

130 

131 for nd in ndFilters: 

132 pf = f"{physical_filter}{FILTER_DELIMITER}{nd}" # fully qualified physical filter 

133 

134 # When one of the filters is empty we can just use the real filter 

135 # (e.g. "u" not "u~empty"); but we always need at least one "empty" 

136 # 

137 # Don't use . in band names, it's just asking for trouble 

138 # if they ever end up in filenames 

139 if nd == "empty": 

140 if band == "empty": 

141 af = "empty" 

142 else: 

143 af = f"{band}" 

144 elif band == "empty": 

145 pf = nd 

146 af = f"{nd.replace('.', '_')}" 

147 else: 

148 af = f"{band}{FILTER_DELIMITER}{nd.replace('.', '_')}" 

149 

150 addFilter(BOTFilters_dict, band=af, physical_filter=pf, lambdaEff=lambdaEff) 

151 

152BOTFilters = [ 

153 FilterDefinition(band="unknown", physical_filter="UNKNOWN", lambdaEff=0.0), 

154] 

155for band, filt in BOTFilters_dict.items(): 

156 BOTFilters.append(FilterDefinition(band=band, 

157 physical_filter=filt["physical_filter"], 

158 lambdaEff=filt["lambdaEff"], 

159 alias=filt["alias"])) 

160# 

161# The filters that we might see in the real LSSTCam (including in SLAC) 

162# 

163# Note that the filters we'll use on the sky, LsstCamFiltersBaseline, must 

164# come first as we're not allocating enough bits in _computeCoaddExposureId 

165# for all the BOT composite filters (i.e. "u~ND_OD1.0") 

166# 

167LSSTCAM_FILTER_DEFINITIONS = FilterDefinitionCollection( 

168 *LsstCamFiltersBaseline, 

169 *BOTFilters, 

170) 

171 

172# 

173# Filters in SLAC's Test Stand 3 

174# 

175TS3Filters = [ 

176 FilterDefinition(band="unknown", physical_filter="UNKNOWN", lambdaEff=0.0), 

177 FilterDefinition(physical_filter="275CutOn", lambdaEff=0.0), 

178 FilterDefinition(physical_filter="550CutOn", lambdaEff=0.0)] 

179 

180TS3_FILTER_DEFINITIONS = FilterDefinitionCollection( 

181 *LsstCamFiltersBaseline, 

182 *TS3Filters, 

183) 

184# 

185# Filters in SLAC's Test Stand 8 

186# 

187TS8Filters = [ 

188 FilterDefinition(band="unknown", physical_filter="UNKNOWN", lambdaEff=0.0), 

189 FilterDefinition(physical_filter="275CutOn", lambdaEff=0.0), 

190 FilterDefinition(physical_filter="550CutOn", lambdaEff=0.0)] 

191 

192TS8_FILTER_DEFINITIONS = FilterDefinitionCollection( 

193 *LsstCamFiltersBaseline, 

194 *TS8Filters, 

195) 

196 

197 

198# LATISS filters include a grating in the name so we need to construct 

199# filters for each combination of filter+grating. 

200_latiss_filters = ( 

201 FilterDefinition(physical_filter="NONE", 

202 lambdaEff=0.0, 

203 alias={"no_filter", "OPEN"}), 

204 FilterDefinition(physical_filter="blank_bk7_wg05", 

205 lambdaEff=0.0), 

206 FilterDefinition(physical_filter="KPNO_1111_436nm", 

207 band="g", 

208 lambdaEff=436.0, lambdaMin=386.0, lambdaMax=486.0), 

209 FilterDefinition(physical_filter="KPNO_373A_677nm", 

210 band="r", 

211 lambdaEff=677.0, lambdaMin=624.0, lambdaMax=730.0), 

212 FilterDefinition(physical_filter="KPNO_406_828nm", 

213 band="z", 

214 lambdaEff=828.0, lambdaMin=738.5, lambdaMax=917.5), 

215 FilterDefinition(physical_filter="diffuser", 

216 lambdaEff=0.0), 

217 FilterDefinition(physical_filter="EMPTY", 

218 lambdaEff=0.0), 

219 FilterDefinition(physical_filter="UNKNOWN", 

220 lambdaEff=0.0), 

221 FilterDefinition(physical_filter="BG40", 

222 # band="g", # afw only allows one g filter 

223 lambdaEff=472.0, lambdaMin=334.5, lambdaMax=609.5), 

224 FilterDefinition(physical_filter="quadnotch1", 

225 lambdaEff=0.0), 

226 FilterDefinition(physical_filter="RG610", 

227 lambdaEff=0.0), 

228) 

229 

230# Form a new set of filter definitions from all the explicit filters 

231_latiss_gratings = ("ronchi90lpmm", "ronchi170lpmm", "EMPTY", "NONE", "UNKNOWN") 

232 

233# Include the filters without the grating in case someone wants 

234# to retrieve a filter by an actual filter name 

235_latiss_filter_and_grating = [f for f in _latiss_filters] 

236 

237for filter in _latiss_filters: 

238 for grating in _latiss_gratings: 

239 # FilterDefinition is a frozen dataclass 

240 new_name = FILTER_DELIMITER.join([filter.physical_filter, grating]) 

241 

242 # Also need to update aliases 

243 new_aliases = {FILTER_DELIMITER.join([a, grating]) for a in filter.alias} 

244 

245 combo = FilterDefinition(physical_filter=new_name, 

246 lambdaEff=filter.lambdaEff, 

247 lambdaMin=filter.lambdaMin, 

248 lambdaMax=filter.lambdaMax, 

249 alias=new_aliases) 

250 _latiss_filter_and_grating.append(combo) 

251 

252 

253LATISS_FILTER_DEFINITIONS = FilterDefinitionCollection(*_latiss_filter_and_grating) 

254 

255 

256LSSTCAM_IMSIM_FILTER_DEFINITIONS = FilterDefinitionCollection( 

257 # These were computed using throughputs 1.4 and 

258 # lsst.sims.photUtils.BandpassSet. 

259 FilterDefinition(physical_filter="u_sim_1.4", 

260 band="u", 

261 lambdaEff=367.070, lambdaMin=308.0, lambdaMax=408.6), 

262 FilterDefinition(physical_filter="g_sim_1.4", 

263 band="g", 

264 lambdaEff=482.685, lambdaMin=386.5, lambdaMax=567.0), 

265 FilterDefinition(physical_filter="r_sim_1.4", 

266 band="r", 

267 lambdaEff=622.324, lambdaMin=537.0, lambdaMax=706.0), 

268 FilterDefinition(physical_filter="i_sim_1.4", 

269 band="i", 

270 lambdaEff=754.598, lambdaMin=676.0, lambdaMax=833.0), 

271 FilterDefinition(physical_filter="z_sim_1.4", 

272 band="z", 

273 lambdaEff=869.090, lambdaMin=803.0, lambdaMax=938.6), 

274 FilterDefinition(physical_filter="y_sim_1.4", 

275 band="y", 

276 lambdaEff=971.028, lambdaMin=908.4, lambdaMax=1096.3) 

277) 

278 

279# ########################################################################### 

280# 

281# ComCam 

282# 

283# See https://jira.lsstcorp.org/browse/DM-21706 

284 

285ComCamFilters_dict = {} 

286for band, sn in [("u", "SN-05"), 

287 ("u", "SN-02"), # not yet coated 

288 ("u", "SN-06"), # not yet coated 

289 ("g", "SN-07"), 

290 ("g", "SN-01"), 

291 ("r", "SN-03"), 

292 ("i", "SN-06"), 

293 ("z", "SN-03"), 

294 ("z", "SN-02"), 

295 ("y", "SN-04"), 

296 ]: 

297 physical_filter = f"{band}_{sn[3:]}" 

298 lsstCamFilter = [f for f in LsstCamFiltersBaseline if f.band == band][0] 

299 lambdaEff = lsstCamFilter.lambdaEff 

300 

301 addFilter(ComCamFilters_dict, band, physical_filter, lambdaEff=lambdaEff) 

302 

303 

304ComCamFilters = [ 

305 FilterDefinition(band="unknown", physical_filter="UNKNOWN", lambdaEff=0.0), 

306] 

307for band, filt in ComCamFilters_dict.items(): 

308 ComCamFilters.append(FilterDefinition(band=band, 

309 physical_filter=filt["physical_filter"], 

310 lambdaEff=filt["lambdaEff"], 

311 alias=filt["alias"])) 

312 

313COMCAM_FILTER_DEFINITIONS = FilterDefinitionCollection( 

314 *ComCamFilters, 

315)