Coverage for python/lsst/obs/lsst/filters.py: 100%

54 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-12 03:28 -0800

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 

31from lsst.obs.base import FilterDefinition, FilterDefinitionCollection 

32from .translators.lsst import FILTER_DELIMITER 

33 

34 

35def addFilter(filter_dict, band, physical_filter): 

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

37 

38 # index by band but keep distinct physical filters by band 

39 # since there can be many physical filters for a single band 

40 if band not in filter_dict: 

41 filter_dict[band] = {} 

42 

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

44 band=band, alias=[], 

45 ) 

46 

47 

48# The LSST Filters from L. Jones 05/14/2020 

49# 

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

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

52 

53LsstCamFiltersBaseline = FilterDefinitionCollection( 

54 FilterDefinition(physical_filter="empty", band="white", 

55 alias={"no_filter", "open"}), 

56 FilterDefinition(physical_filter="u", band="u"), 

57 FilterDefinition(physical_filter="g", band="g"), 

58 FilterDefinition(physical_filter="r", band="r"), 

59 FilterDefinition(physical_filter="i", band="i"), 

60 FilterDefinition(physical_filter="z", band="z"), 

61 FilterDefinition(physical_filter="y", band="y"), 

62) 

63 

64# 

65# Define the filters present in the BOT. 

66# According to Tony Johnson the possible physical filters are 

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

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

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

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

71# where: 

72# ColorFWheel and SpotProjFWheel are mutually exclusive and 

73# both appear in FILTER, 

74# NeutralFWheel appears in FILTER2 

75# 

76# Experimentally we also see FILTER2 values of: 

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

78# 

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

80 

81# Map the BOT filters to corresponding band explicitly 

82BOT_filter_map = { 

83 "empty": "white", 

84 "SDSSu": "u", 

85 "SDSSg": "g", 

86 "SDSSr": "r", 

87 "SDSSi": "i", 

88 "SDSSz": "z", 

89 "SDSSY": "y", 

90 "480nm": "g", 

91 "650nm": "r", 

92 "750nm": "i", 

93 "870nm": "z", 

94 "950nm": "y", 

95 "970nm": "y", 

96 "grid": "grid", 

97 "spot": "spot", 

98} 

99 

100BOTFilters_dict = {} 

101for physical_filter, band in BOT_filter_map.items(): 

102 if physical_filter == "empty": 

103 pass # Already defined above 

104 else: 

105 addFilter(BOTFilters_dict, band, physical_filter) 

106 

107 # Empty ND is removed by metadata translator so is not needed here 

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

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

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

111 

112 for nd in ndFilters: 

113 # fully qualified physical filter 

114 phys_plus_nd = f"{physical_filter}{FILTER_DELIMITER}{nd}" 

115 

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

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

118 if band == "white": 

119 # Use the ND on its own 

120 phys_plus_nd = nd 

121 

122 # Use a generic ND modifier for the band 

123 ndband = f"{band}{FILTER_DELIMITER}nd" 

124 

125 addFilter(BOTFilters_dict, band=ndband, physical_filter=phys_plus_nd) 

126 

127BOTFilters = [ 

128 FilterDefinition(band="unknown", physical_filter="unknown"), 

129] 

130for band, physical_filters in BOTFilters_dict.items(): 

131 for physical_filter, filter_defn in physical_filters.items(): 

132 BOTFilters.append(FilterDefinition(**filter_defn)) 

133 

134# 

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

136# 

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

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

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

140# 

141LSSTCAM_FILTER_DEFINITIONS = FilterDefinitionCollection( 

142 *LsstCamFiltersBaseline, 

143 *BOTFilters, 

144) 

145 

146# 

147# Filters in SLAC's Test Stand 3 

148# 

149TS3Filters = [ 

150 FilterDefinition(band="unknown", physical_filter="unknown"), 

151 FilterDefinition(physical_filter="275CutOn"), 

152 FilterDefinition(physical_filter="550CutOn")] 

153 

154TS3_FILTER_DEFINITIONS = FilterDefinitionCollection( 

155 *LsstCamFiltersBaseline, 

156 *TS3Filters, 

157) 

158# 

159# Filters in SLAC's Test Stand 8 

160# 

161TS8Filters = [ 

162 FilterDefinition(band="unknown", physical_filter="unknown"), 

163 FilterDefinition(physical_filter="275CutOn"), 

164 FilterDefinition(physical_filter="550CutOn")] 

165 

166TS8_FILTER_DEFINITIONS = FilterDefinitionCollection( 

167 *LsstCamFiltersBaseline, 

168 *TS8Filters, 

169) 

170 

171 

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

173# filters for each combination of filter+grating. 

174_latiss_filters = ( 

175 FilterDefinition(physical_filter="empty", 

176 band="white", 

177 alias={"no_filter", "open"}), 

178 FilterDefinition(physical_filter="blank_bk7_wg05", 

179 band="white"), 

180 FilterDefinition(physical_filter="KPNO_1111_436nm", 

181 band="g"), 

182 FilterDefinition(physical_filter="KPNO_373A_677nm", 

183 band="r"), 

184 FilterDefinition(physical_filter="KPNO_406_828nm", 

185 band="z"), 

186 FilterDefinition(physical_filter="diffuser", 

187 band="diffuser"), 

188 FilterDefinition(physical_filter="unknown", 

189 band="unknown"), 

190 FilterDefinition(physical_filter="BG40", 

191 band="g", 

192 afw_name="bg"), 

193 FilterDefinition(physical_filter="BG40_65mm_1", 

194 band="g", 

195 afw_name="bg"), 

196 FilterDefinition(physical_filter="BG40_65mm_2", 

197 band="g", 

198 afw_name="bg"), 

199 FilterDefinition(physical_filter="quadnotch1", 

200 band="notch"), 

201 FilterDefinition(physical_filter="RG610", 

202 band="r", 

203 afw_name="rg"), 

204 FilterDefinition(physical_filter="OG550_65mm_1", 

205 band="g", 

206 afw_name="bg"), 

207 FilterDefinition(physical_filter="OG550_65mm_2", 

208 band="g", 

209 afw_name="bg"), 

210 FilterDefinition(physical_filter="FELH0600", 

211 band="r", 

212 afw_name="rg"), 

213 FilterDefinition(physical_filter="SDSSg", 

214 band="g"), 

215 FilterDefinition(physical_filter="SDSSr", 

216 band="r"), 

217 FilterDefinition(physical_filter="SDSSi", 

218 band="i"), 

219 FilterDefinition(physical_filter="SDSSu_65mm", 

220 band="u"), 

221 FilterDefinition(physical_filter="SDSSg_65mm", 

222 band="g"), 

223 FilterDefinition(physical_filter="SDSSr_65mm", 

224 band="r"), 

225 FilterDefinition(physical_filter="SDSSi_65mm", 

226 band="i"), 

227 FilterDefinition(physical_filter="SDSSz_65mm", 

228 band="z"), 

229 FilterDefinition(physical_filter="SDSSy_65mm", 

230 band="y"), 

231) 

232 

233# Form a new set of filter definitions from all the explicit gratings 

234_latiss_gratings = ("ronchi90lpmm", "ronchi170lpmm", "empty", "unknown", "holo4_003") 

235 

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

237# to retrieve a filter by an actual filter name 

238_latiss_filter_and_grating = [f for f in _latiss_filters] 

239 

240for filter in _latiss_filters: 

241 for grating in _latiss_gratings: 

242 # The diffuser "filter" was never used with gratings 

243 # so skip it 

244 if filter.physical_filter == "diffuser": 

245 continue 

246 

247 # FilterDefinition is a frozen dataclass 

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

249 

250 # Also need to update aliases 

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

252 

253 # For gratings set the band to the band of the filter 

254 combo = FilterDefinition(physical_filter=new_name, 

255 band=filter.band, 

256 afw_name=filter.afw_name, 

257 alias=new_aliases) 

258 _latiss_filter_and_grating.append(combo) 

259 

260 

261LATISS_FILTER_DEFINITIONS = FilterDefinitionCollection(*_latiss_filter_and_grating) 

262 

263 

264LSSTCAM_IMSIM_FILTER_DEFINITIONS = FilterDefinitionCollection( 

265 # These were computed using throughputs 1.4 and 

266 # lsst.sims.photUtils.BandpassSet. 

267 FilterDefinition(physical_filter="u_sim_1.4", 

268 band="u"), 

269 FilterDefinition(physical_filter="g_sim_1.4", 

270 band="g"), 

271 FilterDefinition(physical_filter="r_sim_1.4", 

272 band="r"), 

273 FilterDefinition(physical_filter="i_sim_1.4", 

274 band="i"), 

275 FilterDefinition(physical_filter="z_sim_1.4", 

276 band="z"), 

277 FilterDefinition(physical_filter="y_sim_1.4", 

278 band="y"), 

279) 

280 

281# ########################################################################### 

282# 

283# ComCam 

284# 

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

286 

287ComCamFilters_dict = {} 

288for band, sn in [("u", "SN-05"), # incorrect sub thickness 

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

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

291 ("g", "SN-07"), # bad cosmetics 

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

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

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

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

296 ("z", "SN-02"), # failed specs 

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

298 ]: 

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

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

301 

302 addFilter(ComCamFilters_dict, band, physical_filter) 

303 

304 

305ComCamFilters = [ 

306 FilterDefinition(band="white", physical_filter="empty"), 

307 FilterDefinition(band="unknown", physical_filter="unknown"), 

308] 

309for band, physical_filters in ComCamFilters_dict.items(): 

310 for physical_filter, filter_defn in physical_filters.items(): 

311 ComCamFilters.append(FilterDefinition(**filter_defn)) 

312 

313COMCAM_FILTER_DEFINITIONS = FilterDefinitionCollection( 

314 *ComCamFilters, 

315)