Coverage for src/galsbi/ucat/filters_util.py: 99%

182 statements  

« prev     ^ index     » next       coverage.py v7.17.2, created at 2026-11-09 18:05 +0000

1# Copyright (C) 2018 ETH Zurich, Institute for Particle Physics and Astrophysics 

2 

3""" 

4Created Sept 2021 

5author: Tomasz Kacprzak 

6 

7This script manipulates filter information. It can create the filters_collection.h5 

8file, which contains all listed filters we use. 

9""" 

10 

11import os 

12from collections import OrderedDict 

13 

14import h5py 

15import numpy as np 

16from cosmic_toolbox import logger 

17from scipy.integrate import simpson as simps 

18 

19LOGGER = logger.get_logger(__file__) 

20 

21 

22def create_filter_collection(dirpath_res): 

23 """ 

24 Create a filter collection file 

25 Currently supported instruments: DECam, VISTA, GenericBessel 

26 """ 

27 

28 def add_decam_filters(filters_collect): 

29 # data downloaded from: 

30 # https://noirlab.edu/science/programs/ctio/filters/Dark-Energy-Camera 

31 filepath_filters = os.path.join( 

32 dirpath_res, "filters/filters_DECam/DECam_filters_with_atm.txt" 

33 ) 

34 # LAMBDA g r i z Y atm 

35 filter_data = np.loadtxt(filepath_filters).T 

36 atm = filter_data[-1] 

37 lam = filter_data[0] 

38 for i, b in enumerate(["g", "r", "i", "z", "Y"]): 

39 filters_collect[f"DECam_{b}"] = dict(amp=filter_data[i + 1], lam=lam) 

40 filters_collect[f"DECamNoAtm_{b}"] = dict( 

41 amp=filter_data[i + 1] / atm, lam=lam 

42 ) 

43 LOGGER.info(f"added DECam {b}-band") 

44 

45 b = "u" 

46 decam_u_lam, decam_u_amp = np.loadtxt( 

47 os.path.join(dirpath_res, "filters/filters_DECam/DECam_2014_u.res") 

48 ).T 

49 filters_collect[f"DECam_{b}"] = dict(amp=decam_u_amp, lam=decam_u_lam) 

50 LOGGER.info(f"added DECam {b}-band") 

51 

52 def add_bessel_filters(filters_collect): 

53 # generic Bessel filters from from 

54 # http://adsabs.harvard.edu/abs/1990PASP..102.1181B 

55 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Generic&asttype= 

56 bands = ["B", "I", "R", "U", "V"] 

57 

58 for b in bands: 

59 lam, amp = np.loadtxt( 

60 os.path.join( 

61 dirpath_res, 

62 f"filters/filters_Bessell/Generic_Bessell.{b}.dat" 

63 ) 

64 ).T 

65 filters_collect[f"GenericBessel_{b}"] = dict(amp=amp, lam=lam) 

66 LOGGER.info(f"added GenericBessel {b}-band") 

67 

68 bands = ["J", "H", "K", "L", "M"] 

69 for b in bands: 

70 lam, amp = np.loadtxt( 

71 os.path.join( 

72 dirpath_res, 

73 f"filters/filters_Bessell/Generic_Bessell_JHKLM.{b}.dat" 

74 ) 

75 ).T 

76 filters_collect[f"GenericBessel_{b}"] = dict(amp=amp, lam=lam) 

77 LOGGER.info(f"added GenericBessel {b}-band") 

78 

79 def add_johnson_filters(filters_collect): 

80 # generic Bessel filters from from 

81 # http://adsabs.harvard.edu/abs/1990PASP..102.1181B 

82 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Generic&asttype= 

83 bands = ["U", "B", "V", "R", "I", "J", "M"] 

84 

85 for b in bands: 

86 lam, amp = np.loadtxt( 

87 os.path.join( 

88 dirpath_res, 

89 f"filters/filters_Johnson/Generic_Johnson.{b}.dat" 

90 ) 

91 ).T 

92 filters_collect[f"GenericJohnson_{b}"] = dict(amp=amp, lam=lam) 

93 LOGGER.info(f"added GenericJohnson {b}-band") 

94 

95 def add_cosmos_filters(filters_collect): 

96 # https://ftp.iap.fr/pub/from_users/hjmcc/COSMOS2015/COSMOS2015_Laigle+.header 

97 # https://cosmos.astro.caltech.edu/page/photom 

98 filters = {} 

99 filters["Vircam_Ks"] = dict( 

100 filename="K_uv.res", telescope="VISTA" 

101 ) # Ks_MAG_AUTO 

102 filters["Vircam_Y"] = dict(filename="Y_uv.res", telescope="VISTA") # Y_MAG_AUTO 

103 filters["Vircam_H"] = dict(filename="H_uv.res", telescope="VISTA") # H_MAG_AUTO 

104 filters["Vircam_J"] = dict(filename="J_uv.res", telescope="VISTA") # J_MAG_AUTO 

105 filters["SuprimeCam_B"] = dict( 

106 filename="B_subaru.res", telescope="SUBARU" 

107 ) # B_MAG_AUTO 

108 filters["SuprimeCam_V"] = dict( 

109 filename="V_subaru.res", telescope="SUBARU" 

110 ) # V_MAG_AUTO 

111 filters["SuprimeCam_ip"] = dict( 

112 filename="i_subaru.res", telescope="SUBARU" 

113 ) # ip_MAG_AUTO 

114 filters["SuprimeCam_r"] = dict( 

115 filename="r_subaru.res", telescope="SUBARU" 

116 ) # r_MAG_AUTO 

117 filters["SuprimeCam_zp"] = dict( 

118 filename="z_subaru.res", telescope="SUBARU" 

119 ) # zp_MAG_AUTO 

120 filters["SuprimeCam_zpp"] = dict( 

121 filename="suprime_FDCCD_z.res", telescope="SUBARU" 

122 ) # zpp_MAG_AUTO 

123 filters["MegaPrime_u"] = dict( 

124 filename="u_megaprime_sagem.res", telescope="CFHT" 

125 ) # u_MAG_AUTO 

126 filters["SuprimeCam_IA427"] = dict( 

127 filename="IA427.SuprimeCam.pb", telescope="SUBARU" 

128 ) # IB427_MAG_AUTO 

129 filters["SuprimeCam_IB464"] = dict( 

130 filename="IA464.SuprimeCam.pb", telescope="SUBARU" 

131 ) # IB464_MAG_AUTO 

132 filters["SuprimeCam_IA484"] = dict( 

133 filename="IA484.SuprimeCam.pb", telescope="SUBARU" 

134 ) # IA484_MAG_AUTO 

135 filters["SuprimeCam_IA505"] = dict( 

136 filename="IA505.SuprimeCam.pb", telescope="SUBARU" 

137 ) # IB505_MAG_AUTO 

138 filters["SuprimeCam_IA527"] = dict( 

139 filename="IA527.SuprimeCam.pb", telescope="SUBARU" 

140 ) # IA527_MAG_AUTO 

141 filters["SuprimeCam_IA574"] = dict( 

142 filename="IA574.SuprimeCam.pb", telescope="SUBARU" 

143 ) # IB574_MAG_AUTO 

144 filters["SuprimeCam_IA624"] = dict( 

145 filename="IA624.SuprimeCam.pb", telescope="SUBARU" 

146 ) # IA624_MAG_AUTO 

147 filters["SuprimeCam_IA679"] = dict( 

148 filename="IA679.SuprimeCam.pb", telescope="SUBARU" 

149 ) # IA679_MAG_AUTO 

150 filters["SuprimeCam_IA709"] = dict( 

151 filename="IA709.SuprimeCam.pb", telescope="SUBARU" 

152 ) # IB709_MAG_AUTO 

153 filters["SuprimeCam_IA738"] = dict( 

154 filename="IA738.SuprimeCam.pb", telescope="SUBARU" 

155 ) # IA738_MAG_AUTO 

156 filters["SuprimeCam_IA767"] = dict( 

157 filename="IA767.SuprimeCam.pb", telescope="SUBARU" 

158 ) # IA767_MAG_AUTO 

159 filters["SuprimeCam_IA827"] = dict( 

160 filename="IA827.SuprimeCam.pb", telescope="SUBARU" 

161 ) # IB827_MAG_AUTO 

162 filters["SuprimeCam_NB711"] = dict( 

163 filename="NB711.SuprimeCam.pb", telescope="SUBARU" 

164 ) # NB711_MAG_AUTO 

165 filters["SuprimeCam_NB816"] = dict( 

166 filename="NB816.SuprimeCam.pb", telescope="SUBARU" 

167 ) # NB816_MAG_AUTO 

168 filters["wircam_H"] = dict( 

169 filename="wircam_H.res", telescope="SUBARU" 

170 ) # Hw_MAG_AUTO 

171 filters["wircam_Ks"] = dict( 

172 filename="wircam_Ks.res", telescope="SUBARU" 

173 ) # Ksw_MAG_AUTO 

174 filters["irac_ch1"] = dict( 

175 filename="irac_ch1.res", telescope="SPITZER" 

176 ) # SPLASH_1_MAG 

177 filters["irac_ch2"] = dict( 

178 filename="irac_ch2.res", telescope="SPITZER" 

179 ) # SPLASH_2_MAG 

180 filters["irac_ch3"] = dict( 

181 filename="irac_ch3.res", telescope="SPITZER" 

182 ) # SPLASH_3_MAG 

183 filters["irac_ch4"] = dict( 

184 filename="irac_ch4.res", telescope="SPITZER" 

185 ) # SPLASH_4_MAG 

186 filters["mips_24"] = dict(filename="mips24.res", telescope="SPITZER") # MAG_24 

187 filters["GALEX_FUV"] = dict( 

188 filename="galex1500.res", telescope="GALEX" 

189 ) # MAG_GALEX_FUV 

190 filters["GALEX_NUV"] = dict( 

191 filename="galex2500.res", telescope="GALEX" 

192 ) # MAG_GALEX_NUV 

193 

194 for f in filters: 

195 lam, amp = np.loadtxt( 

196 os.path.join( 

197 dirpath_res, "filters/filters_cosmos2015", filters[f]["filename"] 

198 ) 

199 ).T 

200 filters_collect[f] = dict(amp=amp, lam=lam) 

201 LOGGER.info(f"added Cosmos2015 {f}") 

202 

203 def add_hsc_filters(filters_collect): 

204 # https://hsc-release.mtk.nao.ac.jp/doc/index.php/survey__pdr3/ 

205 # https://hsc-release.mtk.nao.ac.jp/doc/wp-content/uploads/2021/08/hsc_responses_all_rev4.zip 

206 

207 bands = ["g", "r", "r2", "i", "i2", "z", "y"] 

208 for b in bands: 

209 path = os.path.join( 

210 dirpath_res, "filters/filters_hsc_v2018", f"hsc_{b}_v2018.dat" 

211 ) 

212 lam, amp = np.loadtxt(path, comments="#").T 

213 filters_collect[f"HyperSuprimeCam_{b}"] = dict(amp=amp, lam=lam) 

214 LOGGER.info(f"added HyperSuprimeCam_{b}") 

215 

216 def add_sdss_filters(filters_collect): 

217 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=SLOAN 

218 bands = ["u", "g", "r", "i", "z"] 

219 for b in bands: 

220 path = os.path.join(dirpath_res, f"filters/filters_sdss/SLOAN_SDSS.{b}.dat") 

221 lam, amp = np.loadtxt(path).T 

222 filters_collect[f"SDSS_{b}"] = dict(amp=amp, lam=lam) 

223 LOGGER.info(f"added SDSS_{b}") 

224 

225 def add_vista_filters(filters_collect): 

226 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Paranal&gname2=VISTA 

227 bands = ["Z", "Y", "J", "H", "Ks"] 

228 for b in bands: 

229 path = os.path.join( 

230 dirpath_res, f"filters/filters_vista/Paranal_VISTA.{b}.dat" 

231 ) 

232 lam, amp = np.loadtxt(path).T 

233 filters_collect[f"VISTA_{b}"] = dict(amp=amp, lam=lam) 

234 LOGGER.info(f"added VISTA_{b}") 

235 for b in bands: 

236 path = os.path.join( 

237 dirpath_res, 

238 f"filters/filters_vista/Paranal_VISTA.{b}_filter.dat" 

239 ) 

240 lam, amp = np.loadtxt(path).T 

241 filters_collect[f"VISTA_NoAtm{b}"] = dict(amp=amp, lam=lam) 

242 LOGGER.info(f"added VISTA_NoAtm{b}") 

243 

244 def add_omegacam_filters(filters_collect): 

245 # https://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Paranal&gname2=OmegaCAM 

246 bands = ["u", "g", "r", "i", "z"] 

247 for b in bands: 

248 path = os.path.join( 

249 dirpath_res, 

250 f"filters/filters_OmegaCAM/Paranal_OmegaCAM.{b}_SDSS.dat" 

251 ) 

252 lam, amp = np.loadtxt(path).T 

253 filters_collect[f"OmegaCAM_{b}"] = dict(amp=amp, lam=lam) 

254 LOGGER.info(f"added OmegaCAM_{b} filter+CCD") 

255 

256 def add_lsstcam_filters(filters_collect): 

257 # https://github.com/lsst/throughputs/tree/main/baseline 

258 bands = ["u", "g", "r", "i", "z", "y"] 

259 for b in bands: 

260 path = os.path.join( 

261 dirpath_res, 

262 f"filters/filters_LSSTCam/total_{b}.dat" 

263 ) 

264 lam, amp = np.loadtxt(path).T 

265 filters_collect[f"LSSTCam_{b}"] = dict(amp=amp, lam=lam) 

266 LOGGER.info(f"added LSSTCam_{b} mirrors+lenses+filter+detector+atmosphere") 

267 

268 def add_euclid_filters(filters_collect): 

269 # https://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Euclid 

270 path = os.path.join(dirpath_res, "filters/filters_Euclid/Euclid_VIS.vis.dat") 

271 lam, amp = np.loadtxt(path).T 

272 filters_collect["Euclid_VIS"] = dict(amp=amp, lam=lam) 

273 LOGGER.info("added Euclid_VIS filter+instrument") 

274 bands_ir = ["Y", "J", "H"] 

275 for b in bands_ir: 

276 path = os.path.join( 

277 dirpath_res, 

278 f"filters/filters_Euclid/Euclid_NISP.{b}.dat" 

279 ) 

280 lam, amp = np.loadtxt(path).T 

281 filters_collect[f"Euclid_NISP_{b}"] = dict(amp=amp, lam=lam) 

282 LOGGER.info(f"added Euclid_NISP_{b} filter+CCD+instrument+optics") 

283 

284 LOGGER.info("============ creating filter collection") 

285 filters_collect = {} 

286 add_decam_filters(filters_collect) 

287 add_bessel_filters(filters_collect) 

288 add_johnson_filters(filters_collect) 

289 add_cosmos_filters(filters_collect) 

290 add_hsc_filters(filters_collect) 

291 add_sdss_filters(filters_collect) 

292 add_vista_filters(filters_collect) 

293 add_omegacam_filters(filters_collect) 

294 add_lsstcam_filters(filters_collect) 

295 add_euclid_filters(filters_collect) 

296 

297 return filters_collect 

298 

299 

300def store_filter_collection(filepath_collection, filters_collect): 

301 # store collection 

302 n_filters = len(filters_collect) 

303 with h5py.File(filepath_collection, "w") as f: 

304 for b in filters_collect: 

305 for k in filters_collect[b]: 

306 f[f"{b}/{k}"] = filters_collect[b][k] 

307 

308 LOGGER.info(f"wrote {filepath_collection} with {n_filters} filters") 

309 LOGGER.info(filters_collect.keys()) 

310 

311 

312def load_filters(filepath_filters, filter_names=None, lam_scale=1): 

313 filters = OrderedDict() 

314 with h5py.File(filepath_filters, "r") as f: 

315 filter_names = list(f.keys()) if filter_names is None else filter_names 

316 for b in filter_names: 

317 amp = np.array(f[b]["amp"]) 

318 lam = np.array(f[b]["lam"]) * lam_scale 

319 integ = simps(x=lam, y=amp / lam) 

320 LOGGER.debug(f"filter {b} integral={integ:2.5e}") 

321 filters[b] = dict(amp=amp, lam=lam, integ=integ) 

322 return filters 

323 

324 

325class UseShortFilterNames: 

326 """ 

327 Interface between short and long filter names 

328 """ 

329 

330 def __init__(self, func, filters_full_names): 

331 self.func = func 

332 self.filters_full_names = filters_full_names 

333 self.filters_full_names_rev = {ff: fs for fs, ff in filters_full_names.items()} 

334 

335 def __call__(self, **kw): 

336 if "filter_names" in kw: 

337 kw["filter_names"] = [ 

338 self.filters_full_names[f] for f in kw["filter_names"] 

339 ] 

340 

341 out = self.func(**kw) 

342 

343 if not isinstance(out, dict): 

344 return out 

345 else: 

346 out_ = {} 

347 for k in out: 

348 if k in self.filters_full_names_rev: 

349 out_[self.filters_full_names_rev[k]] = out[k] 

350 return out_ 

351 

352 def __getattr__(self, name): 

353 return getattr(self.func, name) 

354 

355 

356def get_default_full_filter_names(filters): 

357 filters_full_names = {f: f for f in filters} 

358 

359 return filters_full_names 

360 

361 

362# 'Ks_MAG_AUTO' Ks_uv.res 

363# 'Y_MAG_AUTO' Y_uv.res 

364# 'H_MAG_AUTO' H_uv.res 

365# 'J_MAG_AUTO' J_uv.res 

366# 'B_MAG_AUTO' B_subaru.res 

367# 'V_MAG_AUTO' V_subaru.res 

368# 'ip_MAG_AUTO' i_Subaru.res 

369# 'r_MAG_AUTO' r_subaru.res 

370# 'zp_MAG_AUTO' z_subaru.res 

371# 'zpp_MAG_AUTO' suprime_FDCCD_z.res 

372# 'u_MAG_AUTO' u_megaprime_sagem.res 

373# 'IB427_MAG_AUTO' IB427.SuprimeCam.pb 

374# 'IB464_MAG_AUTO' IB464.SuprimeCam.pb 

375# 'IA484_MAG_AUTO' IA484.SuprimeCam.pb 

376# 'IB505_MAG_AUTO' IB505.SuprimeCam.pb 

377# 'IA527_MAG_AUTO' IA527.SuprimeCam.pb 

378# 'IB574_MAG_AUTO' IB574.SuprimeCam.pb 

379# 'IA624_MAG_AUTO' IA624.SuprimeCam.pb 

380# 'IA679_MAG_AUTO' IA679.SuprimeCam.pb 

381# 'IB709_MAG_AUTO' IB709.SuprimeCam.pb 

382# 'IA738_MAG_AUTO' IA738.SuprimeCam.pb 

383# 'IA767_MAG_AUTO' IA767.SuprimeCam.pb 

384# 'IB827_MAG_AUTO' IB827.SuprimeCam.pb 

385# 'NB711_MAG_AUTO' NB711.SuprimeCam.pb 

386# 'NB816_MAG_AUTO' NB816.SuprimeCam.pb 

387# 'Hw_MAG_AUTO' wircam_H.res 

388# 'Ksw_MAG_AUTO' wircam_Ks.res 

389# 'yHSC_MAG_AUTO' y_HSC.txt 

390# 'SPLASH_1_MAG', irac_ch1.res 

391# 'SPLASH_2_MAG', irac_ch2.res 

392# 'SPLASH_3_MAG', irac_ch3.res 

393# 'SPLASH_4_MAG', irac_ch4.res 

394# 'MAG_24', mips24.res 

395# 'MAG_GALEX_FUV' galex1500.res 

396# 'MAG_GALEX_NUV' galex2500.res