astro-otter 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astro_otter-0.6.0.dist-info/METADATA +161 -0
- astro_otter-0.6.0.dist-info/RECORD +18 -0
- astro_otter-0.6.0.dist-info/WHEEL +5 -0
- astro_otter-0.6.0.dist-info/licenses/LICENSE +21 -0
- astro_otter-0.6.0.dist-info/top_level.txt +1 -0
- otter/__init__.py +19 -0
- otter/_version.py +5 -0
- otter/exceptions.py +74 -0
- otter/io/__init__.py +0 -0
- otter/io/data_finder.py +1045 -0
- otter/io/host.py +186 -0
- otter/io/otter.py +1594 -0
- otter/io/transient.py +1453 -0
- otter/plotter/__init__.py +0 -0
- otter/plotter/otter_plotter.py +76 -0
- otter/plotter/plotter.py +266 -0
- otter/schema.py +312 -0
- otter/util.py +850 -0
otter/util.py
ADDED
|
@@ -0,0 +1,850 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Some constants, mappings, and functions to be used across the software
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from itertools import chain
|
|
7
|
+
import os
|
|
8
|
+
from multiprocessing import Pool
|
|
9
|
+
import ads
|
|
10
|
+
from ads.exceptions import APIResponseError
|
|
11
|
+
import json
|
|
12
|
+
import astropy.units as u
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
Helper functions first that just don't belong anywhere else
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def filter_to_obstype(band_name):
|
|
21
|
+
"""
|
|
22
|
+
Converts a band name to either 'radio', 'uvoir', 'xray'
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
wave_eff = FILTER_MAP_WAVE[band_name] * u.nm
|
|
27
|
+
except KeyError as exc:
|
|
28
|
+
raise Exception(
|
|
29
|
+
f"No Effective Wavelength Known for {band_name}, please add it to constants"
|
|
30
|
+
) from exc
|
|
31
|
+
|
|
32
|
+
return wave_to_obstype(wave_eff)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def freq_to_obstype(freq_eff):
|
|
36
|
+
"""
|
|
37
|
+
Converts a frequency value to either 'radio', 'uvoir', 'xray'
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
freq_eff (u.Quantity) : An astropy quantity in frequency space
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
wave_eff = freq_eff.to(u.nm, equivalencies=u.spectral())
|
|
44
|
+
return wave_to_obstype(wave_eff)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def wave_to_obstype(wave_eff):
|
|
48
|
+
"""
|
|
49
|
+
Converts a wavelength value to either 'radio', 'uvoir', 'xray'
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
wave_eff (u.Quantity) : An astropy quantity in wavelength space
|
|
53
|
+
"""
|
|
54
|
+
if wave_eff > 0.1 * u.mm:
|
|
55
|
+
return "radio"
|
|
56
|
+
elif wave_eff <= 0.1 * u.mm and wave_eff >= 10 * u.nm:
|
|
57
|
+
return "uvoir"
|
|
58
|
+
else:
|
|
59
|
+
return "xray"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def clean_schema(schema):
|
|
63
|
+
"""
|
|
64
|
+
Clean out Nones and empty lists from the given subschema
|
|
65
|
+
"""
|
|
66
|
+
for key, val in list(schema.items()):
|
|
67
|
+
if val is None or (isinstance(val, (list, dict)) and len(val) == 0):
|
|
68
|
+
del schema[key]
|
|
69
|
+
return schema
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def bibcode_to_hrn(bibcode, local_reference_map="reference_map_local.json"):
|
|
73
|
+
if isinstance(bibcode, str):
|
|
74
|
+
bibcode = [bibcode]
|
|
75
|
+
|
|
76
|
+
if os.path.exists(local_reference_map):
|
|
77
|
+
with open(local_reference_map, "r") as j:
|
|
78
|
+
local_map = json.load(j)
|
|
79
|
+
else:
|
|
80
|
+
local_map = {}
|
|
81
|
+
|
|
82
|
+
hrns = []
|
|
83
|
+
bibcodes = []
|
|
84
|
+
bibcodes_to_query = []
|
|
85
|
+
for b in bibcode:
|
|
86
|
+
if b in local_map:
|
|
87
|
+
hrns.append(local_map[b])
|
|
88
|
+
bibcodes.append(b)
|
|
89
|
+
else:
|
|
90
|
+
bibcodes_to_query.append(b)
|
|
91
|
+
|
|
92
|
+
if len(bibcodes_to_query) > 0:
|
|
93
|
+
queried_bibs, queried_hrns = _bibcode_to_hrn_with_query(bibcodes_to_query)
|
|
94
|
+
hrns += queried_hrns
|
|
95
|
+
bibcodes += queried_bibs
|
|
96
|
+
|
|
97
|
+
return bibcodes, hrns
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _bibcode_to_hrn_with_query(bibcode):
|
|
101
|
+
"""
|
|
102
|
+
Converts a bibcode to a human_readable_name (hrn) using ADSQuery
|
|
103
|
+
"""
|
|
104
|
+
if isinstance(bibcode, str):
|
|
105
|
+
bibcode = bibcode.strip()
|
|
106
|
+
query = f"bibcode:{bibcode}"
|
|
107
|
+
bibcodes = [bibcode]
|
|
108
|
+
else:
|
|
109
|
+
# make sure the bibcodes are lists instead of strings of lists
|
|
110
|
+
bibcode = [b.strip("[]").replace("'", "").split(", ") for b in bibcode]
|
|
111
|
+
|
|
112
|
+
bibcode = list(chain(*[v if isinstance(v, list) else [v] for v in bibcode]))
|
|
113
|
+
|
|
114
|
+
bibcodes_flat = np.array(bibcode).flatten()
|
|
115
|
+
bibcodes_cleaned = np.array([b.strip() for b in bibcodes_flat])
|
|
116
|
+
|
|
117
|
+
bibcodes = list(np.unique(bibcodes_cleaned))
|
|
118
|
+
|
|
119
|
+
protected_vals = ["private", "new", "current work"]
|
|
120
|
+
for val in protected_vals:
|
|
121
|
+
if val in bibcodes:
|
|
122
|
+
bibcodes.pop(bibcodes.index(val))
|
|
123
|
+
|
|
124
|
+
if len(bibcodes) == 0:
|
|
125
|
+
# then all of the bibcodes were "private"
|
|
126
|
+
return bibcodes, bibcodes
|
|
127
|
+
|
|
128
|
+
query = f"bibcode:{bibcodes[0]}"
|
|
129
|
+
if len(bibcodes) > 1:
|
|
130
|
+
for b in bibcodes[1:]:
|
|
131
|
+
query += f" OR {b}"
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
qobj = ads.SearchQuery(q=query)
|
|
135
|
+
qobj.execute() # do the query
|
|
136
|
+
adsquery = list(qobj)
|
|
137
|
+
except IndexError:
|
|
138
|
+
raise ValueError(f"Could not find {bibcode} on ADS!")
|
|
139
|
+
except APIResponseError as exc:
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"""Failed on query {query}! \n Potentially out of ADS
|
|
142
|
+
queries! Run curl command to check like\n
|
|
143
|
+
https://github.com/adsabs/adsabs-dev-api/blob/master/README.md"""
|
|
144
|
+
) from exc
|
|
145
|
+
|
|
146
|
+
hrns = []
|
|
147
|
+
bibcodes_to_return = []
|
|
148
|
+
for res in adsquery:
|
|
149
|
+
authors = res.author
|
|
150
|
+
year = res.year
|
|
151
|
+
|
|
152
|
+
if len(authors) == 0:
|
|
153
|
+
raise ValueError("This ADS bibcode does not exist!")
|
|
154
|
+
elif len(authors) == 1:
|
|
155
|
+
author = authors[0]
|
|
156
|
+
elif len(authors) == 2:
|
|
157
|
+
author = authors[0] + " & " + authors[1]
|
|
158
|
+
else: # longer than 2
|
|
159
|
+
author = authors[0] + " et al."
|
|
160
|
+
|
|
161
|
+
# generate the human readable name
|
|
162
|
+
hrn = author + " (" + year + ")"
|
|
163
|
+
hrns.append(hrn)
|
|
164
|
+
bibcodes_to_return.append(res.bibcode)
|
|
165
|
+
|
|
166
|
+
if len(hrns) == 0 and len(bibcodes) != 0:
|
|
167
|
+
raise ValueError(f"Could not find any bibcodes associated with {bibcodes}!")
|
|
168
|
+
|
|
169
|
+
if isinstance(bibcode, str):
|
|
170
|
+
return hrns[0]
|
|
171
|
+
|
|
172
|
+
if len(hrns) != len(bibcodes):
|
|
173
|
+
raise ValueError(
|
|
174
|
+
f"ADS has multiple sources associated with one of these bibcodes! \
|
|
175
|
+
{bibcode}"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return bibcodes_to_return, hrns
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def freq_to_band(freq: u.Quantity) -> str:
|
|
182
|
+
"""
|
|
183
|
+
Converts an effective frequency to the corresponding band name based on the
|
|
184
|
+
standards listed in RADIO_BAND_MAPPING
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
freq (astropy Quantity) : Astropy Quantity of the frequency to get the band name
|
|
188
|
+
Returns:
|
|
189
|
+
string with the commonly used band name
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
for key, freq_range in RADIO_BAND_MAPPING.items():
|
|
193
|
+
if freq_range[0] * u.GHz < freq <= freq_range[1] * u.GHz:
|
|
194
|
+
return key
|
|
195
|
+
|
|
196
|
+
raise ValueError(f"No band name found for the frequency {freq}. Please verify that \
|
|
197
|
+
it is in a range in RADIO_BAND_MAPPING and, if not, add it!")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _wrap_single_conversion(t):
|
|
201
|
+
"""
|
|
202
|
+
t is a tuple of (frequency, unit)
|
|
203
|
+
"""
|
|
204
|
+
return freq_to_band(t[0] * u.Unit(t[1]))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def freqlist_to_band(
|
|
208
|
+
freq_list: list[float], freq_unit_list: list[str], ncores=1
|
|
209
|
+
) -> list[str]:
|
|
210
|
+
"""
|
|
211
|
+
Converts a list of effective frequencies to the corresponding band names based on
|
|
212
|
+
the standards listed in RADIO_BAND_MAPPING
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
freq_list (list[float]): floats for the frequencies
|
|
216
|
+
freq_unit_list (list[str]): List of astropy unit strings to apply to freq_list
|
|
217
|
+
ncores (int): The number of cores to multiprocess with
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
list of strings with the band names
|
|
221
|
+
"""
|
|
222
|
+
with Pool(ncores) as p:
|
|
223
|
+
return p.map(_wrap_single_conversion, zip(freq_list, freq_unit_list))
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
"""
|
|
227
|
+
Then the constants and dictionary mappings used throughout
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
# gives the effective wavelength for each filter given
|
|
231
|
+
# these are all in nanometers!
|
|
232
|
+
FILTER_MAP_WAVE = {
|
|
233
|
+
"FUV": 153.8620701901866,
|
|
234
|
+
"NUV": 231.56631043707714,
|
|
235
|
+
"UVW2": 207.98754332676123,
|
|
236
|
+
"uvw2": 207.98754332676123,
|
|
237
|
+
"W2": 207.98754332676123,
|
|
238
|
+
"2": 207.98754332676123,
|
|
239
|
+
"uw2": 207.98754332676123,
|
|
240
|
+
"UVM2": 225.47802478793594,
|
|
241
|
+
"uvm2": 225.47802478793594,
|
|
242
|
+
"M2": 225.47802478793594,
|
|
243
|
+
"M": 225.47802478793594,
|
|
244
|
+
"um2": 225.47802478793594,
|
|
245
|
+
"UVW1": 261.3713060531025,
|
|
246
|
+
"uvw1": 261.3713060531025,
|
|
247
|
+
"W1": 261.3713060531025,
|
|
248
|
+
"1": 261.3713060531025,
|
|
249
|
+
"uw1": 261.3713060531025,
|
|
250
|
+
"u": 356.17887353001856,
|
|
251
|
+
"u'": 356.17887353001856,
|
|
252
|
+
"up": 356.17887353001856,
|
|
253
|
+
"uprime": 356.17887353001856,
|
|
254
|
+
"U_S": 347.06360491031495,
|
|
255
|
+
"s": 347.06360491031495,
|
|
256
|
+
"us": 347.06360491031495,
|
|
257
|
+
"U": 353.10502283105023,
|
|
258
|
+
"B": 443.0539845758355,
|
|
259
|
+
"B_S": 435.912081730874,
|
|
260
|
+
"b": 435.912081730874,
|
|
261
|
+
"bs": 435.912081730874,
|
|
262
|
+
"g": 471.8872246248687,
|
|
263
|
+
"g'": 471.8872246248687,
|
|
264
|
+
"gp": 471.8872246248687,
|
|
265
|
+
"gprime": 471.8872246248687,
|
|
266
|
+
"F475W": 471.8872246248687,
|
|
267
|
+
"g-DECam": 482.6787274749997,
|
|
268
|
+
"c": 540.8724658332794,
|
|
269
|
+
"cyan": 540.8724658332794,
|
|
270
|
+
"V": 553.7155963302753,
|
|
271
|
+
"V_S": 543.0131091205997,
|
|
272
|
+
"v": 543.0131091205997,
|
|
273
|
+
"vs": 543.0131091205997,
|
|
274
|
+
"Itagaki": 651.0535687558726,
|
|
275
|
+
"white": 752.0,
|
|
276
|
+
"unfilt.": 616.690135,
|
|
277
|
+
"0": 616.690135,
|
|
278
|
+
"C": 616.690135,
|
|
279
|
+
"clear": 616.690135,
|
|
280
|
+
"pseudobolometric": 616.690135,
|
|
281
|
+
"griz": 616.690135,
|
|
282
|
+
"RGB": 616.690135,
|
|
283
|
+
"LGRB": 616.690135,
|
|
284
|
+
"G": 673.5412573108297,
|
|
285
|
+
"Kepler": 641.6835660569259,
|
|
286
|
+
"TESS": 797.2360657697333,
|
|
287
|
+
"DLT40": 615.8130149792426,
|
|
288
|
+
"Open": 615.8130149792426,
|
|
289
|
+
"Clear": 615.8130149792426,
|
|
290
|
+
"w": 638.9300625093831,
|
|
291
|
+
"o": 686.6260690394873,
|
|
292
|
+
"orange": 686.6260690394873,
|
|
293
|
+
"r": 618.5194476741524,
|
|
294
|
+
"r'": 618.5194476741524,
|
|
295
|
+
"rp": 618.5194476741524,
|
|
296
|
+
"rprime": 618.5194476741524,
|
|
297
|
+
"F625W": 618.5194476741524,
|
|
298
|
+
"r-DECam": 643.2062638192127,
|
|
299
|
+
"R": 646.9439215118385,
|
|
300
|
+
"Rc": 646.9439215118385,
|
|
301
|
+
"R_s": 646.9439215118385,
|
|
302
|
+
"i": 749.9704174464691,
|
|
303
|
+
"i'": 749.9704174464691,
|
|
304
|
+
"ip": 749.9704174464691,
|
|
305
|
+
"iprime": 749.9704174464691,
|
|
306
|
+
"F775W": 749.9704174464691,
|
|
307
|
+
"i-DECam": 782.6680306208917,
|
|
308
|
+
"I": 788.558706467662,
|
|
309
|
+
"Ic": 788.558706467662,
|
|
310
|
+
"z_s": 867.9495480864285,
|
|
311
|
+
"zs": 867.9495480864285,
|
|
312
|
+
"z": 896.1488333992431,
|
|
313
|
+
"z'": 896.1488333992431,
|
|
314
|
+
"zp": 896.1488333992431,
|
|
315
|
+
"zprime": 896.1488333992431,
|
|
316
|
+
"z-DECam": 917.8949537472383,
|
|
317
|
+
"y": 963.3308299506817,
|
|
318
|
+
"y-DECam": 989.965087304703,
|
|
319
|
+
"J": 1255.0918319447906,
|
|
320
|
+
"H": 1630.5155019191195,
|
|
321
|
+
"K": 2157.3600605745955,
|
|
322
|
+
"Ks": 2157.3600605745955,
|
|
323
|
+
"F070W": 705.5727879998312,
|
|
324
|
+
"F090W": 904.2281265089156,
|
|
325
|
+
"F115W": 1157.001589027877,
|
|
326
|
+
"F150W": 1503.9880463410511,
|
|
327
|
+
"F200W": 1993.3922957570885,
|
|
328
|
+
"F225W": 2372.81,
|
|
329
|
+
"F277W": 2769.332372846113,
|
|
330
|
+
"F300M": 2990.7606605760484,
|
|
331
|
+
"F335M": 3363.887076210947,
|
|
332
|
+
"F356W": 3576.787256375927,
|
|
333
|
+
"F360M": 3626.0578695682693,
|
|
334
|
+
"F444W": 4415.974447587756,
|
|
335
|
+
"F560W": 5645.279496731566,
|
|
336
|
+
"F770W": 7663.455798629626,
|
|
337
|
+
"F1000W": 9968.161727011531,
|
|
338
|
+
"F1130W": 11310.984595876938,
|
|
339
|
+
"F1280W": 12831.396996921212,
|
|
340
|
+
"F1500W": 15091.367399905488,
|
|
341
|
+
"F1800W": 18006.083119653664,
|
|
342
|
+
"F2100W": 20842.526633138932,
|
|
343
|
+
"F2550W": 25408.228367890282,
|
|
344
|
+
}
|
|
345
|
+
"""
|
|
346
|
+
Mapping for the effective wavelength in nanometers for all filters used in the dataset.
|
|
347
|
+
"""
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# gives the effective frequency for all filters
|
|
351
|
+
# These are all in THz
|
|
352
|
+
FILTER_MAP_FREQ = {
|
|
353
|
+
"FUV": 1975.086895569116,
|
|
354
|
+
"NUV": 1346.3548820463916,
|
|
355
|
+
"UVW2": 1531.4976984760474,
|
|
356
|
+
"uvw2": 1531.4976984760474,
|
|
357
|
+
"W2": 1531.4976984760474,
|
|
358
|
+
"2": 1531.4976984760474,
|
|
359
|
+
"uw2": 1531.4976984760474,
|
|
360
|
+
"UVM2": 1360.083095675749,
|
|
361
|
+
"uvm2": 1360.083095675749,
|
|
362
|
+
"M2": 1360.083095675749,
|
|
363
|
+
"M": 1360.083095675749,
|
|
364
|
+
"um2": 1360.083095675749,
|
|
365
|
+
"UVW1": 1236.8527545450256,
|
|
366
|
+
"uvw1": 1236.8527545450256,
|
|
367
|
+
"W1": 1236.8527545450256,
|
|
368
|
+
"1": 1236.8527545450256,
|
|
369
|
+
"uw1": 1236.8527545450256,
|
|
370
|
+
"u": 849.2871562331687,
|
|
371
|
+
"u'": 849.2871562331687,
|
|
372
|
+
"up": 849.2871562331687,
|
|
373
|
+
"uprime": 849.2871562331687,
|
|
374
|
+
"U_S": 875.611103788721,
|
|
375
|
+
"s": 875.611103788721,
|
|
376
|
+
"us": 875.611103788721,
|
|
377
|
+
"U": 858.321721875779,
|
|
378
|
+
"B": 688.8500955332158,
|
|
379
|
+
"B_S": 696.7876979144597,
|
|
380
|
+
"b": 696.7876979144597,
|
|
381
|
+
"bs": 696.7876979144597,
|
|
382
|
+
"g": 648.9823425403824,
|
|
383
|
+
"g'": 648.9823425403824,
|
|
384
|
+
"gp": 648.9823425403824,
|
|
385
|
+
"gprime": 648.9823425403824,
|
|
386
|
+
"F475W": 648.9823425403824,
|
|
387
|
+
"g-DECam": 635.8015668464043,
|
|
388
|
+
"c": 580.1132515050684,
|
|
389
|
+
"cyan": 580.1132515050684,
|
|
390
|
+
"V": 548.3068934496129,
|
|
391
|
+
"V_S": 554.9815375506427,
|
|
392
|
+
"v": 554.9815375506427,
|
|
393
|
+
"vs": 554.9815375506427,
|
|
394
|
+
"Itagaki": 577.0861573682259,
|
|
395
|
+
"white": 30079.243284322874,
|
|
396
|
+
"unfilt.": 601.5655810567023,
|
|
397
|
+
"0": 601.5655810567023,
|
|
398
|
+
"C": 601.5655810567023,
|
|
399
|
+
"clear": 601.5655810567023,
|
|
400
|
+
"pseudobolometric": 601.5655810567023,
|
|
401
|
+
"griz": 601.5655810567023,
|
|
402
|
+
"RGB": 601.5655810567023,
|
|
403
|
+
"LGRB": 601.5655810567023,
|
|
404
|
+
"G": 518.6766845466752,
|
|
405
|
+
"Kepler": 519.5058608954615,
|
|
406
|
+
"TESS": 403.1881955125893,
|
|
407
|
+
"DLT40": 629.637672549936,
|
|
408
|
+
"Open": 629.637672549936,
|
|
409
|
+
"Clear": 629.637672549936,
|
|
410
|
+
"w": 520.8387777057242,
|
|
411
|
+
"o": 451.71177203298663,
|
|
412
|
+
"orange": 451.71177203298663,
|
|
413
|
+
"r": 489.2629992899134,
|
|
414
|
+
"r'": 489.2629992899134,
|
|
415
|
+
"rp": 489.2629992899134,
|
|
416
|
+
"rprime": 489.2629992899134,
|
|
417
|
+
"F625W": 489.2629992899134,
|
|
418
|
+
"r-DECam": 472.4459671948087,
|
|
419
|
+
"R": 471.26223689126897,
|
|
420
|
+
"Rc": 471.26223689126897,
|
|
421
|
+
"R_s": 471.26223689126897,
|
|
422
|
+
"i": 402.8409598867557,
|
|
423
|
+
"i'": 402.8409598867557,
|
|
424
|
+
"ip": 402.8409598867557,
|
|
425
|
+
"iprime": 402.8409598867557,
|
|
426
|
+
"F775W": 402.8409598867557,
|
|
427
|
+
"i-DECam": 386.62233825433924,
|
|
428
|
+
"I": 382.7915178046724,
|
|
429
|
+
"Ic": 382.7915178046724,
|
|
430
|
+
"z_s": 346.66628641927826,
|
|
431
|
+
"zs": 346.66628641927826,
|
|
432
|
+
"z": 337.7343708777923,
|
|
433
|
+
"z'": 337.7343708777923,
|
|
434
|
+
"zp": 337.7343708777923,
|
|
435
|
+
"zprime": 337.7343708777923,
|
|
436
|
+
"z-DECam": 328.753462451287,
|
|
437
|
+
"y": 312.24818210606065,
|
|
438
|
+
"y-DECam": 303.4727730182509,
|
|
439
|
+
"J": 239.862442505934,
|
|
440
|
+
"H": 185.33613196897403,
|
|
441
|
+
"K": 139.79431978859097,
|
|
442
|
+
"Ks": 139.79431978859097,
|
|
443
|
+
"F070W": 431.04176743403116,
|
|
444
|
+
"F090W": 336.17431986268366,
|
|
445
|
+
"F115W": 262.87628654288676,
|
|
446
|
+
"F150W": 201.94374815011136,
|
|
447
|
+
"F200W": 152.56522352568953,
|
|
448
|
+
"F277W": 110.05136786468209,
|
|
449
|
+
"F300M": 100.56915203596012,
|
|
450
|
+
"F335M": 89.41072625742719,
|
|
451
|
+
"F356W": 85.01984846997881,
|
|
452
|
+
"F360M": 82.9357933095218,
|
|
453
|
+
"F444W": 68.96667222373961,
|
|
454
|
+
"F560W": 53.67852315133938,
|
|
455
|
+
"F770W": 39.87175477126777,
|
|
456
|
+
"F1000W": 30.349460503852665,
|
|
457
|
+
"F1130W": 26.53952983680919,
|
|
458
|
+
"F1280W": 23.59741975845449,
|
|
459
|
+
"F1500W": 20.08679352819493,
|
|
460
|
+
"F1800W": 16.773842151606242,
|
|
461
|
+
"F2100W": 14.581938602646188,
|
|
462
|
+
"F2550W": 11.919267708332558,
|
|
463
|
+
}
|
|
464
|
+
"""
|
|
465
|
+
Mapping for the effective frequencies in THz for all the filters used in OTTER
|
|
466
|
+
"""
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
# x-ray telescope areas for converting
|
|
470
|
+
# NOTE: these are estimates from the links provided
|
|
471
|
+
# Since this is inherently instrument dependent they are not entirely reliable
|
|
472
|
+
# All are for 1-2 keV
|
|
473
|
+
XRAY_AREAS = {
|
|
474
|
+
# https://swift.gsfc.nasa.gov/about_swift/Sci_Fact_Sheet.pdf
|
|
475
|
+
"swift": 135 * u.cm**2,
|
|
476
|
+
"swift-xrt": 135 * u.cm**2,
|
|
477
|
+
# https://heasarc.gsfc.nasa.gov/docs/rosat/ruh/handbook/node39.html#SECTION00634000000000000000
|
|
478
|
+
"rosat": 400 * u.cm**2,
|
|
479
|
+
# https://www.cosmos.esa.int/web/xmm-newton/technical-details-mirrors
|
|
480
|
+
"xmm": 1500 * u.cm**2,
|
|
481
|
+
"xmm slew": 1500 * u.cm**2,
|
|
482
|
+
"xmm-slew": 1500 * u.cm**2,
|
|
483
|
+
"xmm pointed": 1500 * u.cm**2,
|
|
484
|
+
"xmm-newton": 1500 * u.cm**2,
|
|
485
|
+
# https://cxc.harvard.edu/cdo/about_chandra
|
|
486
|
+
"chandra": 600 * u.cm**2,
|
|
487
|
+
# https://www.cosmos.esa.int/documents/332006/954765/Brunner_TopicK.pdf
|
|
488
|
+
"erosita": 1500 * u.cm**2,
|
|
489
|
+
# https://en.wikipedia.org/wiki/NuSTAR
|
|
490
|
+
"nustar": 847 * u.cm**2,
|
|
491
|
+
# https://iss.jaxa.jp/en/kiboexp/ef/maxi/
|
|
492
|
+
"maxi": 200 * u.cm**2,
|
|
493
|
+
# https://iopscience.iop.org/article/10.3847/1538-4357/abd569
|
|
494
|
+
"konus-wind": 120 * u.cm**2,
|
|
495
|
+
# https://www.cosmos.esa.int/web/einstein-probe/mission
|
|
496
|
+
"ep": 600 * u.cm**2,
|
|
497
|
+
"ep-fxt": 600 * u.cm**2,
|
|
498
|
+
}
|
|
499
|
+
"""
|
|
500
|
+
X-Ray telescope areas that are used for converting from counts to other units.
|
|
501
|
+
|
|
502
|
+
NOTE: These are estimates from the following links
|
|
503
|
+
* https://swift.gsfc.nasa.gov/about_swift/Sci_Fact_Sheet.pdf
|
|
504
|
+
* https://heasarc.gsfc.nasa.gov/docs/rosat/ruh/handbook/node39.html#SECTION00634000000000000000
|
|
505
|
+
* https://www.cosmos.esa.int/web/xmm-newton/technical-details-mirrors
|
|
506
|
+
* https://cxc.harvard.edu/cdo/about_chandra
|
|
507
|
+
"""
|
|
508
|
+
|
|
509
|
+
# Radio Band names with frequency ranges in GHz
|
|
510
|
+
RADIO_BAND_MAPPING = {
|
|
511
|
+
# use some lower bands from IEEE standards up to GMRT standards
|
|
512
|
+
# These are mostly here just as catchalls for low frequency radio telescopes
|
|
513
|
+
# like GEETEE or LOFAR
|
|
514
|
+
"HF": (0.003, 0.03),
|
|
515
|
+
"VHF": (0.03, 0.125), # Official: (0.03, 0.3) but adjust to work with GMRT standard
|
|
516
|
+
# use GMRT standards for low frequencies
|
|
517
|
+
"gmrt.2": (0.125, 0.250),
|
|
518
|
+
"gmrt.3": (0.25, 0.55), # Official: (0.25, 0.5)
|
|
519
|
+
# IEEE Standard Naming
|
|
520
|
+
# https://terasense.com/terahertz-technology/radio-frequency-bands/
|
|
521
|
+
"UHF": (0.55, 1),
|
|
522
|
+
"L": (1, 2),
|
|
523
|
+
"S": (2, 4),
|
|
524
|
+
"C": (4, 8),
|
|
525
|
+
"X": (8, 12),
|
|
526
|
+
"Ku": (12, 18),
|
|
527
|
+
"K": (18, 27),
|
|
528
|
+
"Ka": (27, 40),
|
|
529
|
+
# then switch to ALMA standard for mm
|
|
530
|
+
# https://www.eso.org/public/teles-instr/alma/receiver-bands/
|
|
531
|
+
# I widened some of the official ranges slightly so we don't leave gaps
|
|
532
|
+
# although these gaps probably wouldn't have mattered because **atmosphere**
|
|
533
|
+
"alma.1": (40, 50), # Official: (35, 50)
|
|
534
|
+
"alma.3": (84, 116), # skip alma.2 cause it's just a smaller range of alma.3
|
|
535
|
+
"alma.4": (116, 163), # official: (125, 163)
|
|
536
|
+
"alma.5": (163, 211),
|
|
537
|
+
"alma.6": (211, 275),
|
|
538
|
+
"alma.7": (275, 373),
|
|
539
|
+
"alma.8": (373, 500), # official: (385,500)
|
|
540
|
+
"alma.9": (500, 720), # official: (602, 720)
|
|
541
|
+
"alma.10": (787, 950),
|
|
542
|
+
}
|
|
543
|
+
"""
|
|
544
|
+
Mapping of common radio/mm band names to their corresponding frequency ranges.
|
|
545
|
+
All frequencies are in GHz. The upperlimit is inclusive, that is these ranges
|
|
546
|
+
are really (xx, yy].
|
|
547
|
+
"""
|
|
548
|
+
|
|
549
|
+
# define a working base directory constant
|
|
550
|
+
BASEDIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
551
|
+
"""
|
|
552
|
+
Base directory for the OTTER API software package
|
|
553
|
+
"""
|
|
554
|
+
|
|
555
|
+
VIZIER_LARGE_CATALOGS = [
|
|
556
|
+
"2MASS-PSC",
|
|
557
|
+
"2MASX",
|
|
558
|
+
"AC2000.2",
|
|
559
|
+
"AKARI",
|
|
560
|
+
"ALLWISE",
|
|
561
|
+
"ASCC-2.5",
|
|
562
|
+
"B/DENIS",
|
|
563
|
+
"CMC14",
|
|
564
|
+
"Gaia-DR1",
|
|
565
|
+
"GALEX",
|
|
566
|
+
"GLIMPSE",
|
|
567
|
+
"GSC-ACT",
|
|
568
|
+
"GSC1.2",
|
|
569
|
+
"GSC2.2",
|
|
570
|
+
"GSC2.3",
|
|
571
|
+
"HIP",
|
|
572
|
+
"HIP2",
|
|
573
|
+
"IRAS",
|
|
574
|
+
"NOMAD1",
|
|
575
|
+
"NVSS",
|
|
576
|
+
"PanSTARRS-DR1",
|
|
577
|
+
"PGC",
|
|
578
|
+
"Planck-DR1",
|
|
579
|
+
"PPMX",
|
|
580
|
+
"PPMXL",
|
|
581
|
+
"SDSS-DR12",
|
|
582
|
+
"SDSS-DR7",
|
|
583
|
+
"SDSS-DR9",
|
|
584
|
+
"Tycho-2",
|
|
585
|
+
"UCAC2",
|
|
586
|
+
"UCAC3",
|
|
587
|
+
"UCAC4",
|
|
588
|
+
"UKIDSS",
|
|
589
|
+
"USNO-A2",
|
|
590
|
+
"USNO-B1",
|
|
591
|
+
"WISE",
|
|
592
|
+
]
|
|
593
|
+
"""
|
|
594
|
+
ViZier catalog names that we query for host information in the Host class
|
|
595
|
+
"""
|
|
596
|
+
|
|
597
|
+
_KNOWN_CLASS_ROOTS = [
|
|
598
|
+
"SN",
|
|
599
|
+
"SLSN",
|
|
600
|
+
"TDE",
|
|
601
|
+
"GRB",
|
|
602
|
+
"LGRB",
|
|
603
|
+
"SGRB",
|
|
604
|
+
"AGN",
|
|
605
|
+
"FRB",
|
|
606
|
+
"QSO",
|
|
607
|
+
"ANT",
|
|
608
|
+
]
|
|
609
|
+
"""
|
|
610
|
+
Classification root names
|
|
611
|
+
"""
|
|
612
|
+
|
|
613
|
+
DATADIR = os.path.join(BASEDIR, "data", "base")
|
|
614
|
+
"""
|
|
615
|
+
Deprecated database directory that IS NOT always constant anymore
|
|
616
|
+
"""
|
|
617
|
+
|
|
618
|
+
####################################################################
|
|
619
|
+
# The following schema dictionaries are here so the code remains
|
|
620
|
+
# backwards compatible. BUT! All future code should use the pydantic
|
|
621
|
+
# schema defined in schema.py
|
|
622
|
+
####################################################################
|
|
623
|
+
|
|
624
|
+
# Overarching schema that stops once we get down to a string or list
|
|
625
|
+
schema = {
|
|
626
|
+
"schema_version": {"value": "0", "comment": "Copied from tde.space"},
|
|
627
|
+
"name": {"default_name": None, "alias": []},
|
|
628
|
+
"coordinate": [],
|
|
629
|
+
"distance": [],
|
|
630
|
+
"classification": {"value": []},
|
|
631
|
+
"reference_alias": [],
|
|
632
|
+
"date_reference": [],
|
|
633
|
+
"photometry": [],
|
|
634
|
+
"spectra": [],
|
|
635
|
+
"filter_alias": [],
|
|
636
|
+
}
|
|
637
|
+
"""
|
|
638
|
+
Schema dictionary to be filled with values from the subschemas
|
|
639
|
+
"""
|
|
640
|
+
|
|
641
|
+
# sub schemas that get filled into lists
|
|
642
|
+
name_alias_schema = {"value": None, "reference": None}
|
|
643
|
+
"""
|
|
644
|
+
Subschema for the name and alias dictionary
|
|
645
|
+
"""
|
|
646
|
+
|
|
647
|
+
coordinate_schema = {
|
|
648
|
+
"ra": None,
|
|
649
|
+
"dec": None,
|
|
650
|
+
"l": None,
|
|
651
|
+
"b": None,
|
|
652
|
+
"lon": None,
|
|
653
|
+
"lat": None,
|
|
654
|
+
"ra_units": None,
|
|
655
|
+
"dec_units": None,
|
|
656
|
+
"l_units": None,
|
|
657
|
+
"b_units": None,
|
|
658
|
+
"lon_units": None,
|
|
659
|
+
"lat_units": None,
|
|
660
|
+
"ra_error": None,
|
|
661
|
+
"dec_error": None,
|
|
662
|
+
"l_error": None,
|
|
663
|
+
"b_error": None,
|
|
664
|
+
"lon_error": None,
|
|
665
|
+
"lat_error": None,
|
|
666
|
+
"epoch": None,
|
|
667
|
+
"frame": None,
|
|
668
|
+
"coord_type": None,
|
|
669
|
+
"computed": None,
|
|
670
|
+
"reference": None,
|
|
671
|
+
"default": None,
|
|
672
|
+
}
|
|
673
|
+
"""
|
|
674
|
+
Subschema to describe the possible attributes for the coordinate dictionary
|
|
675
|
+
"""
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
distance_schema = {
|
|
679
|
+
"value": None,
|
|
680
|
+
"unit": None,
|
|
681
|
+
"error": None,
|
|
682
|
+
"cosmology": None,
|
|
683
|
+
"reference": None,
|
|
684
|
+
"computed": None,
|
|
685
|
+
"uuid": None,
|
|
686
|
+
"default": None,
|
|
687
|
+
"distance_type": None,
|
|
688
|
+
}
|
|
689
|
+
"""
|
|
690
|
+
Subschema to describe the possible attributes for the distance dictionary
|
|
691
|
+
"""
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
classification_schema = {
|
|
695
|
+
"object_class": None,
|
|
696
|
+
"confidence": None,
|
|
697
|
+
"class_type": None,
|
|
698
|
+
"reference": None,
|
|
699
|
+
"default": None,
|
|
700
|
+
}
|
|
701
|
+
"""
|
|
702
|
+
Subschema to describe the attributes for the classification dictionary
|
|
703
|
+
"""
|
|
704
|
+
|
|
705
|
+
reference_alias_schema = {"name": None, "human_readable_name": None}
|
|
706
|
+
"""
|
|
707
|
+
Subschema to describe the attributes for the reference alias dictionary
|
|
708
|
+
"""
|
|
709
|
+
|
|
710
|
+
date_reference_schema = {
|
|
711
|
+
"value": None,
|
|
712
|
+
"date_format": None,
|
|
713
|
+
"date_type": None,
|
|
714
|
+
"reference": None,
|
|
715
|
+
"computed": None,
|
|
716
|
+
}
|
|
717
|
+
"""
|
|
718
|
+
Subschema to describe the date_reference dictionary attributes
|
|
719
|
+
"""
|
|
720
|
+
|
|
721
|
+
photometry_schema = {
|
|
722
|
+
"raw": None,
|
|
723
|
+
"raw_err": None,
|
|
724
|
+
"raw_units": None,
|
|
725
|
+
"value": None,
|
|
726
|
+
"value_err": None,
|
|
727
|
+
"value_units": None,
|
|
728
|
+
"epoch_zeropoint": None,
|
|
729
|
+
"epoch_redshift": None,
|
|
730
|
+
"filter": None,
|
|
731
|
+
"filter_key": None,
|
|
732
|
+
"obs_type": None,
|
|
733
|
+
"telescope_area": None,
|
|
734
|
+
"date": None,
|
|
735
|
+
"date_format": None,
|
|
736
|
+
"date_err": None,
|
|
737
|
+
"ignore": None,
|
|
738
|
+
"upperlimit": None,
|
|
739
|
+
"sigma": None,
|
|
740
|
+
"sky": None,
|
|
741
|
+
"telescope": None,
|
|
742
|
+
"instrument": None,
|
|
743
|
+
"phot_type": None,
|
|
744
|
+
"exptime": None,
|
|
745
|
+
"aperature": None,
|
|
746
|
+
"observer": None,
|
|
747
|
+
"reducer": None,
|
|
748
|
+
"pipeline": None,
|
|
749
|
+
"corr_k": None,
|
|
750
|
+
"corr_av": None,
|
|
751
|
+
"corr_host": None,
|
|
752
|
+
"corr_hostav": None,
|
|
753
|
+
"val_k": None,
|
|
754
|
+
"val_s": None,
|
|
755
|
+
"val_av": None,
|
|
756
|
+
"val_host": None,
|
|
757
|
+
"val_hostav": None,
|
|
758
|
+
}
|
|
759
|
+
"""
|
|
760
|
+
Subschema to describe all of the possible attributes that can be used in the photometry
|
|
761
|
+
dictionary
|
|
762
|
+
"""
|
|
763
|
+
|
|
764
|
+
spectra_schema = {
|
|
765
|
+
"wavelength": None,
|
|
766
|
+
"wavelength_units": None,
|
|
767
|
+
"flux": None,
|
|
768
|
+
"fluxerr": None,
|
|
769
|
+
"raw": None,
|
|
770
|
+
"raw_err": None,
|
|
771
|
+
"sky": None,
|
|
772
|
+
"lamp": None,
|
|
773
|
+
"flux_units": None,
|
|
774
|
+
"telescope": None,
|
|
775
|
+
"instrument": None,
|
|
776
|
+
"date": None,
|
|
777
|
+
"date_format": None,
|
|
778
|
+
"date_err": None,
|
|
779
|
+
"exptime": None,
|
|
780
|
+
"slit": None,
|
|
781
|
+
"airmass": None,
|
|
782
|
+
"disperser": None,
|
|
783
|
+
"resolution": None,
|
|
784
|
+
"resolution_units": None,
|
|
785
|
+
"min_wave": None,
|
|
786
|
+
"max_wave": None,
|
|
787
|
+
"filter": None,
|
|
788
|
+
"filter_key": None,
|
|
789
|
+
"standard_name": None,
|
|
790
|
+
"ignore": None,
|
|
791
|
+
"spec_type": None,
|
|
792
|
+
"aperture": None,
|
|
793
|
+
"observer": None,
|
|
794
|
+
"reducer": None,
|
|
795
|
+
"pipeline": None,
|
|
796
|
+
"corr_k": None,
|
|
797
|
+
"corr_av": None,
|
|
798
|
+
"corr_host": None,
|
|
799
|
+
"corr_hostav": None,
|
|
800
|
+
"corr_flux": None,
|
|
801
|
+
"corr_phot": None,
|
|
802
|
+
"val_k": None,
|
|
803
|
+
"val_av": None,
|
|
804
|
+
"val_host": None,
|
|
805
|
+
"val_hostav": None,
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
filter_alias_schema = {
|
|
809
|
+
"filter_key": None,
|
|
810
|
+
"wave_eff": None,
|
|
811
|
+
"wave_min": None,
|
|
812
|
+
"wave_max": None,
|
|
813
|
+
"freq_eff": None,
|
|
814
|
+
"freq_min": None,
|
|
815
|
+
"freq_max": None,
|
|
816
|
+
"zp": None,
|
|
817
|
+
"wave_units": None,
|
|
818
|
+
"freq_units": None,
|
|
819
|
+
"zp_units": None,
|
|
820
|
+
"zp_system": None,
|
|
821
|
+
}
|
|
822
|
+
"""
|
|
823
|
+
Subschema to describe the attributes in the filter_alias dictionary
|
|
824
|
+
"""
|
|
825
|
+
|
|
826
|
+
# package the subschemas by the key used for that location in the Transient object
|
|
827
|
+
subschema = {
|
|
828
|
+
"name/alias": name_alias_schema,
|
|
829
|
+
"coordinate": coordinate_schema,
|
|
830
|
+
"distance": distance_schema,
|
|
831
|
+
"classification": classification_schema,
|
|
832
|
+
"reference_alias": reference_alias_schema,
|
|
833
|
+
"date_reference": date_reference_schema,
|
|
834
|
+
"photometry": photometry_schema,
|
|
835
|
+
"spectra": spectra_schema,
|
|
836
|
+
"filter_alias": filter_alias_schema,
|
|
837
|
+
}
|
|
838
|
+
"""
|
|
839
|
+
A useful variable to describe all of the subschemas that are available and can be used
|
|
840
|
+
"""
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
class _DuplicateFilter(object):
|
|
844
|
+
def __init__(self):
|
|
845
|
+
self.msgs = set()
|
|
846
|
+
|
|
847
|
+
def filter(self, record):
|
|
848
|
+
rv = record.msg not in self.msgs
|
|
849
|
+
self.msgs.add(record.msg)
|
|
850
|
+
return rv
|