Coverage for src/galsbi/ucat/filters_util.py: 99%
154 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-03 17:18 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-03 17:18 +0000
1# Copyright (C) 2018 ETH Zurich, Institute for Particle Physics and Astrophysics
3"""
4Created Sept 2021
5author: Tomasz Kacprzak
7This script manipulates filter information. It can create the filters_collection.h5
8file, which contains all listed filters we use.
9"""
11import os
12from collections import OrderedDict
14import h5py
15import numpy as np
16from cosmic_toolbox import logger
17from scipy.integrate import simpson as simps
19LOGGER = logger.get_logger(__file__)
22def create_filter_collection(dirpath_res):
23 """
24 Create a filter collection file
25 Currently supported instruments: DECam, VISTA, GenericBessel
26 """
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/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")
45 b = "u"
46 decam_u_lam, decam_u_amp = np.loadtxt(
47 os.path.join(dirpath_res, "filters/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")
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"]
58 for b in bands:
59 lam, amp = np.loadtxt(
60 os.path.join(dirpath_res, f"filters/Generic_Bessell.{b}.dat")
61 ).T
62 filters_collect[f"GenericBessel_{b}"] = dict(amp=amp, lam=lam)
63 LOGGER.info(f"added GenericBessel {b}-band")
65 bands = ["J", "H", "K", "L", "M"]
66 for b in bands:
67 lam, amp = np.loadtxt(
68 os.path.join(dirpath_res, f"filters/Generic_Bessell_JHKLM.{b}.dat")
69 ).T
70 filters_collect[f"GenericBessel_{b}"] = dict(amp=amp, lam=lam)
71 LOGGER.info(f"added GenericBessel {b}-band")
73 def add_johnson_filters(filters_collect):
74 # generic Bessel filters from from
75 # http://adsabs.harvard.edu/abs/1990PASP..102.1181B
76 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Generic&asttype=
77 bands = ["U", "B", "V", "R", "I", "J", "M"]
79 for b in bands:
80 lam, amp = np.loadtxt(
81 os.path.join(dirpath_res, f"filters/Generic_Johnson.{b}.dat")
82 ).T
83 filters_collect[f"GenericJohnson_{b}"] = dict(amp=amp, lam=lam)
84 LOGGER.info(f"added GenericJohnson {b}-band")
86 def add_cosmos_filters(filters_collect):
87 # https://ftp.iap.fr/pub/from_users/hjmcc/COSMOS2015/COSMOS2015_Laigle+.header
88 # https://cosmos.astro.caltech.edu/page/photom
89 filters = {}
90 filters["Vircam_Ks"] = dict(
91 filename="K_uv.res", telescope="VISTA"
92 ) # Ks_MAG_AUTO
93 filters["Vircam_Y"] = dict(filename="Y_uv.res", telescope="VISTA") # Y_MAG_AUTO
94 filters["Vircam_H"] = dict(filename="H_uv.res", telescope="VISTA") # H_MAG_AUTO
95 filters["Vircam_J"] = dict(filename="J_uv.res", telescope="VISTA") # J_MAG_AUTO
96 filters["SuprimeCam_B"] = dict(
97 filename="B_subaru.res", telescope="SUBARU"
98 ) # B_MAG_AUTO
99 filters["SuprimeCam_V"] = dict(
100 filename="V_subaru.res", telescope="SUBARU"
101 ) # V_MAG_AUTO
102 filters["SuprimeCam_ip"] = dict(
103 filename="i_subaru.res", telescope="SUBARU"
104 ) # ip_MAG_AUTO
105 filters["SuprimeCam_r"] = dict(
106 filename="r_subaru.res", telescope="SUBARU"
107 ) # r_MAG_AUTO
108 filters["SuprimeCam_zp"] = dict(
109 filename="z_subaru.res", telescope="SUBARU"
110 ) # zp_MAG_AUTO
111 filters["SuprimeCam_zpp"] = dict(
112 filename="suprime_FDCCD_z.res", telescope="SUBARU"
113 ) # zpp_MAG_AUTO
114 filters["MegaPrime_u"] = dict(
115 filename="u_megaprime_sagem.res", telescope="CFHT"
116 ) # u_MAG_AUTO
117 filters["SuprimeCam_IA427"] = dict(
118 filename="IA427.SuprimeCam.pb", telescope="SUBARU"
119 ) # IB427_MAG_AUTO
120 filters["SuprimeCam_IB464"] = dict(
121 filename="IA464.SuprimeCam.pb", telescope="SUBARU"
122 ) # IB464_MAG_AUTO
123 filters["SuprimeCam_IA484"] = dict(
124 filename="IA484.SuprimeCam.pb", telescope="SUBARU"
125 ) # IA484_MAG_AUTO
126 filters["SuprimeCam_IA505"] = dict(
127 filename="IA505.SuprimeCam.pb", telescope="SUBARU"
128 ) # IB505_MAG_AUTO
129 filters["SuprimeCam_IA527"] = dict(
130 filename="IA527.SuprimeCam.pb", telescope="SUBARU"
131 ) # IA527_MAG_AUTO
132 filters["SuprimeCam_IA574"] = dict(
133 filename="IA574.SuprimeCam.pb", telescope="SUBARU"
134 ) # IB574_MAG_AUTO
135 filters["SuprimeCam_IA624"] = dict(
136 filename="IA624.SuprimeCam.pb", telescope="SUBARU"
137 ) # IA624_MAG_AUTO
138 filters["SuprimeCam_IA679"] = dict(
139 filename="IA679.SuprimeCam.pb", telescope="SUBARU"
140 ) # IA679_MAG_AUTO
141 filters["SuprimeCam_IA709"] = dict(
142 filename="IA709.SuprimeCam.pb", telescope="SUBARU"
143 ) # IB709_MAG_AUTO
144 filters["SuprimeCam_IA738"] = dict(
145 filename="IA738.SuprimeCam.pb", telescope="SUBARU"
146 ) # IA738_MAG_AUTO
147 filters["SuprimeCam_IA767"] = dict(
148 filename="IA767.SuprimeCam.pb", telescope="SUBARU"
149 ) # IA767_MAG_AUTO
150 filters["SuprimeCam_IA827"] = dict(
151 filename="IA827.SuprimeCam.pb", telescope="SUBARU"
152 ) # IB827_MAG_AUTO
153 filters["SuprimeCam_NB711"] = dict(
154 filename="NB711.SuprimeCam.pb", telescope="SUBARU"
155 ) # NB711_MAG_AUTO
156 filters["SuprimeCam_NB816"] = dict(
157 filename="NB816.SuprimeCam.pb", telescope="SUBARU"
158 ) # NB816_MAG_AUTO
159 filters["wircam_H"] = dict(
160 filename="wircam_H.res", telescope="SUBARU"
161 ) # Hw_MAG_AUTO
162 filters["wircam_Ks"] = dict(
163 filename="wircam_Ks.res", telescope="SUBARU"
164 ) # Ksw_MAG_AUTO
165 filters["irac_ch1"] = dict(
166 filename="irac_ch1.res", telescope="SPITZER"
167 ) # SPLASH_1_MAG
168 filters["irac_ch2"] = dict(
169 filename="irac_ch2.res", telescope="SPITZER"
170 ) # SPLASH_2_MAG
171 filters["irac_ch3"] = dict(
172 filename="irac_ch3.res", telescope="SPITZER"
173 ) # SPLASH_3_MAG
174 filters["irac_ch4"] = dict(
175 filename="irac_ch4.res", telescope="SPITZER"
176 ) # SPLASH_4_MAG
177 filters["mips_24"] = dict(filename="mips24.res", telescope="SPITZER") # MAG_24
178 filters["GALEX_FUV"] = dict(
179 filename="galex1500.res", telescope="GALEX"
180 ) # MAG_GALEX_FUV
181 filters["GALEX_NUV"] = dict(
182 filename="galex2500.res", telescope="GALEX"
183 ) # MAG_GALEX_NUV
185 for f in filters:
186 lam, amp = np.loadtxt(
187 os.path.join(
188 dirpath_res, "filters/filters_cosmos2015", filters[f]["filename"]
189 )
190 ).T
191 filters_collect[f] = dict(amp=amp, lam=lam)
192 LOGGER.info(f"added Cosmos2015 {f}")
194 def add_hsc_filters(filters_collect):
195 # https://hsc-release.mtk.nao.ac.jp/doc/index.php/survey__pdr3/
196 # https://hsc-release.mtk.nao.ac.jp/doc/wp-content/uploads/2021/08/hsc_responses_all_rev4.zip
198 bands = ["g", "r", "r2", "i", "i2", "z", "y"]
199 for b in bands:
200 path = os.path.join(
201 dirpath_res, "filters/filters_hsc_v2018", f"hsc_{b}_v2018.dat"
202 )
203 lam, amp = np.loadtxt(path, comments="#").T
204 filters_collect[f"HyperSuprimeCam_{b}"] = dict(amp=amp, lam=lam)
205 LOGGER.info(f"added HyperSuprimeCam_{b}")
207 def add_sdss_filters(filters_collect):
208 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=SLOAN
209 bands = ["u", "g", "r", "i", "z"]
210 for b in bands:
211 path = os.path.join(dirpath_res, f"filters/filters_sdss/SLOAN_SDSS.{b}.dat")
212 lam, amp = np.loadtxt(path).T
213 filters_collect[f"SDSS_{b}"] = dict(amp=amp, lam=lam)
214 LOGGER.info(f"added SDSS_{b}")
216 def add_vista_filters(filters_collect):
217 # http://svo2.cab.inta-csic.es/svo/theory/fps3/index.php?mode=browse&gname=Paranal&gname2=VISTA
218 bands = ["Z", "Y", "J", "H", "Ks"]
219 for b in bands:
220 path = os.path.join(
221 dirpath_res, f"filters/filters_vista/Paranal_VISTA.{b}.dat"
222 )
223 lam, amp = np.loadtxt(path).T
224 filters_collect[f"VISTA_{b}"] = dict(amp=amp, lam=lam)
225 LOGGER.info(f"added VISTA_{b}")
226 for b in bands:
227 path = os.path.join(
228 dirpath_res, f"filters/filters_vista/Paranal_VISTA.{b}_filter.dat"
229 )
230 lam, amp = np.loadtxt(path).T
231 filters_collect[f"VISTA_NoAtm{b}"] = dict(amp=amp, lam=lam)
232 LOGGER.info(f"added VISTA_NoAtm{b}")
234 LOGGER.info("============ creating filter collection")
235 filters_collect = {}
236 add_decam_filters(filters_collect)
237 add_bessel_filters(filters_collect)
238 add_johnson_filters(filters_collect)
239 add_cosmos_filters(filters_collect)
240 add_hsc_filters(filters_collect)
241 add_sdss_filters(filters_collect)
242 add_vista_filters(filters_collect)
244 return filters_collect
247def store_filter_collection(filepath_collection, filters_collect):
248 # store collection
249 n_filters = len(filters_collect)
250 with h5py.File(filepath_collection, "w") as f:
251 for b in filters_collect:
252 for k in filters_collect[b]:
253 f[f"{b}/{k}"] = filters_collect[b][k]
255 LOGGER.info(f"wrote {filepath_collection} with {n_filters} filters")
256 LOGGER.info(filters_collect.keys())
259def load_filters(filepath_filters, filter_names=None, lam_scale=1):
260 filters = OrderedDict()
261 with h5py.File(filepath_filters, "r") as f:
262 filter_names = list(f.keys()) if filter_names is None else filter_names
263 for b in filter_names:
264 amp = np.array(f[b]["amp"])
265 lam = np.array(f[b]["lam"]) * lam_scale
266 integ = simps(x=lam, y=amp / lam)
267 LOGGER.debug(f"filter {b} integral={integ:2.5e}")
268 filters[b] = dict(amp=amp, lam=lam, integ=integ)
269 return filters
272class UseShortFilterNames:
273 """
274 Interface between short and long filter names
275 """
277 def __init__(self, func, filters_full_names):
278 self.func = func
279 self.filters_full_names = filters_full_names
280 self.filters_full_names_rev = {ff: fs for fs, ff in filters_full_names.items()}
282 def __call__(self, **kw):
283 if "filter_names" in kw:
284 kw["filter_names"] = [
285 self.filters_full_names[f] for f in kw["filter_names"]
286 ]
288 out = self.func(**kw)
290 if not isinstance(out, dict):
291 return out
292 else:
293 out_ = {}
294 for k in out:
295 if k in self.filters_full_names_rev:
296 out_[self.filters_full_names_rev[k]] = out[k]
297 return out_
299 def __getattr__(self, name):
300 return getattr(self.func, name)
303def get_default_full_filter_names(filters):
304 filters_full_names = {f: f for f in filters}
306 return filters_full_names
309# 'Ks_MAG_AUTO' Ks_uv.res
310# 'Y_MAG_AUTO' Y_uv.res
311# 'H_MAG_AUTO' H_uv.res
312# 'J_MAG_AUTO' J_uv.res
313# 'B_MAG_AUTO' B_subaru.res
314# 'V_MAG_AUTO' V_subaru.res
315# 'ip_MAG_AUTO' i_Subaru.res
316# 'r_MAG_AUTO' r_subaru.res
317# 'zp_MAG_AUTO' z_subaru.res
318# 'zpp_MAG_AUTO' suprime_FDCCD_z.res
319# 'u_MAG_AUTO' u_megaprime_sagem.res
320# 'IB427_MAG_AUTO' IB427.SuprimeCam.pb
321# 'IB464_MAG_AUTO' IB464.SuprimeCam.pb
322# 'IA484_MAG_AUTO' IA484.SuprimeCam.pb
323# 'IB505_MAG_AUTO' IB505.SuprimeCam.pb
324# 'IA527_MAG_AUTO' IA527.SuprimeCam.pb
325# 'IB574_MAG_AUTO' IB574.SuprimeCam.pb
326# 'IA624_MAG_AUTO' IA624.SuprimeCam.pb
327# 'IA679_MAG_AUTO' IA679.SuprimeCam.pb
328# 'IB709_MAG_AUTO' IB709.SuprimeCam.pb
329# 'IA738_MAG_AUTO' IA738.SuprimeCam.pb
330# 'IA767_MAG_AUTO' IA767.SuprimeCam.pb
331# 'IB827_MAG_AUTO' IB827.SuprimeCam.pb
332# 'NB711_MAG_AUTO' NB711.SuprimeCam.pb
333# 'NB816_MAG_AUTO' NB816.SuprimeCam.pb
334# 'Hw_MAG_AUTO' wircam_H.res
335# 'Ksw_MAG_AUTO' wircam_Ks.res
336# 'yHSC_MAG_AUTO' y_HSC.txt
337# 'SPLASH_1_MAG', irac_ch1.res
338# 'SPLASH_2_MAG', irac_ch2.res
339# 'SPLASH_3_MAG', irac_ch3.res
340# 'SPLASH_4_MAG', irac_ch4.res
341# 'MAG_24', mips24.res
342# 'MAG_GALEX_FUV' galex1500.res
343# 'MAG_GALEX_NUV' galex2500.res