astro-otter 0.1.0__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of astro-otter might be problematic. Click here for more details.
- {astro_otter-0.1.0.dist-info → astro_otter-0.3.0.dist-info}/METADATA +53 -16
- astro_otter-0.3.0.dist-info/RECORD +18 -0
- {astro_otter-0.1.0.dist-info → astro_otter-0.3.0.dist-info}/WHEEL +1 -1
- otter/__init__.py +4 -1
- otter/_version.py +1 -1
- otter/io/data_finder.py +306 -13
- otter/io/host.py +80 -0
- otter/io/otter.py +781 -13
- otter/io/transient.py +221 -87
- otter/plotter/otter_plotter.py +6 -4
- otter/plotter/plotter.py +180 -2
- otter/schema.py +296 -0
- otter/util.py +258 -59
- astro_otter-0.1.0.dist-info/RECORD +0 -17
- {astro_otter-0.1.0.dist-info → astro_otter-0.3.0.dist-info/licenses}/LICENSE +0 -0
- {astro_otter-0.1.0.dist-info → astro_otter-0.3.0.dist-info}/top_level.txt +0 -0
otter/util.py
CHANGED
|
@@ -3,9 +3,14 @@ Some constants, mappings, and functions to be used across the software
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
|
+
from itertools import chain
|
|
6
7
|
import os
|
|
8
|
+
from multiprocessing import Pool
|
|
7
9
|
import ads
|
|
10
|
+
from ads.exceptions import APIResponseError
|
|
11
|
+
import json
|
|
8
12
|
import astropy.units as u
|
|
13
|
+
import numpy as np
|
|
9
14
|
|
|
10
15
|
"""
|
|
11
16
|
Helper functions first that just don't belong anywhere else
|
|
@@ -24,9 +29,31 @@ def filter_to_obstype(band_name):
|
|
|
24
29
|
f"No Effective Wavelength Known for {band_name}, please add it to constants"
|
|
25
30
|
) from exc
|
|
26
31
|
|
|
27
|
-
|
|
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:
|
|
28
55
|
return "radio"
|
|
29
|
-
elif wave_eff <= 1 * u.mm and wave_eff >= 10 * u.nm:
|
|
56
|
+
elif wave_eff <= 0.1 * u.mm and wave_eff >= 10 * u.nm:
|
|
30
57
|
return "uvoir"
|
|
31
58
|
else:
|
|
32
59
|
return "xray"
|
|
@@ -42,31 +69,154 @@ def clean_schema(schema):
|
|
|
42
69
|
return schema
|
|
43
70
|
|
|
44
71
|
|
|
45
|
-
def bibcode_to_hrn(bibcode):
|
|
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):
|
|
46
101
|
"""
|
|
47
102
|
Converts a bibcode to a human_readable_name (hrn) using ADSQuery
|
|
48
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
|
+
query = f"bibcode:{bibcodes[0]}"
|
|
125
|
+
if len(bibcodes) > 1:
|
|
126
|
+
for b in bibcodes[1:]:
|
|
127
|
+
query += f" OR {b}"
|
|
49
128
|
|
|
50
129
|
try:
|
|
51
|
-
|
|
130
|
+
qobj = ads.SearchQuery(q=query)
|
|
131
|
+
qobj.execute() # do the query
|
|
132
|
+
adsquery = list(qobj)
|
|
52
133
|
except IndexError:
|
|
53
134
|
raise ValueError(f"Could not find {bibcode} on ADS!")
|
|
135
|
+
except APIResponseError as exc:
|
|
136
|
+
raise ValueError(
|
|
137
|
+
f"""Failed on query {query}! \n Potentially out of ADS
|
|
138
|
+
queries! Run curl command to check like\n
|
|
139
|
+
https://github.com/adsabs/adsabs-dev-api/blob/master/README.md"""
|
|
140
|
+
) from exc
|
|
141
|
+
|
|
142
|
+
hrns = []
|
|
143
|
+
bibcodes_to_return = []
|
|
144
|
+
for res in adsquery:
|
|
145
|
+
authors = res.author
|
|
146
|
+
year = res.year
|
|
54
147
|
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
if len(authors) == 0:
|
|
149
|
+
raise ValueError("This ADS bibcode does not exist!")
|
|
150
|
+
elif len(authors) == 1:
|
|
151
|
+
author = authors[0]
|
|
152
|
+
elif len(authors) == 2:
|
|
153
|
+
author = authors[0] + " & " + authors[1]
|
|
154
|
+
else: # longer than 2
|
|
155
|
+
author = authors[0] + " et al."
|
|
57
156
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
elif len(authors) == 2:
|
|
63
|
-
author = authors[0] + " & " + authors[1]
|
|
64
|
-
else: # longer than 2
|
|
65
|
-
author = authors[0] + " et al."
|
|
157
|
+
# generate the human readable name
|
|
158
|
+
hrn = author + " (" + year + ")"
|
|
159
|
+
hrns.append(hrn)
|
|
160
|
+
bibcodes_to_return.append(res.bibcode)
|
|
66
161
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
162
|
+
if len(hrns) == 0 and len(bibcodes) != 0:
|
|
163
|
+
raise ValueError(f"Could not find any bibcodes associated with {bibcodes}!")
|
|
164
|
+
|
|
165
|
+
if isinstance(bibcode, str):
|
|
166
|
+
return hrns[0]
|
|
167
|
+
|
|
168
|
+
if len(hrns) != len(bibcodes):
|
|
169
|
+
raise ValueError(
|
|
170
|
+
f"ADS has multiple sources associated with one of these bibcodes! \
|
|
171
|
+
{bibcode}"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return bibcodes_to_return, hrns
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def freq_to_band(freq: u.Quantity) -> str:
|
|
178
|
+
"""
|
|
179
|
+
Converts an effective frequency to the corresponding band name based on the
|
|
180
|
+
standards listed in RADIO_BAND_MAPPING
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
freq (astropy Quantity) : Astropy Quantity of the frequency to get the band name
|
|
184
|
+
Returns:
|
|
185
|
+
string with the commonly used band name
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
for key, freq_range in RADIO_BAND_MAPPING.items():
|
|
189
|
+
if freq_range[0] * u.GHz < freq <= freq_range[1] * u.GHz:
|
|
190
|
+
return key
|
|
191
|
+
|
|
192
|
+
raise ValueError(f"No band name found for the frequency {freq}. Please verify that \
|
|
193
|
+
it is in a range in RADIO_BAND_MAPPING and, if not, add it!")
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _wrap_single_conversion(t):
|
|
197
|
+
"""
|
|
198
|
+
t is a tuple of (frequency, unit)
|
|
199
|
+
"""
|
|
200
|
+
return freq_to_band(t[0] * u.Unit(t[1]))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def freqlist_to_band(
|
|
204
|
+
freq_list: list[float], freq_unit_list: list[str], ncores=1
|
|
205
|
+
) -> list[str]:
|
|
206
|
+
"""
|
|
207
|
+
Converts a list of effective frequencies to the corresponding band names based on
|
|
208
|
+
the standards listed in RADIO_BAND_MAPPING
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
freq_list (list[float]): floats for the frequencies
|
|
212
|
+
freq_unit_list (list[str]): List of astropy unit strings to apply to freq_list
|
|
213
|
+
ncores (int): The number of cores to multiprocess with
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
list of strings with the band names
|
|
217
|
+
"""
|
|
218
|
+
with Pool(ncores) as p:
|
|
219
|
+
return p.map(_wrap_single_conversion, zip(freq_list, freq_unit_list))
|
|
70
220
|
|
|
71
221
|
|
|
72
222
|
"""
|
|
@@ -324,9 +474,13 @@ XRAY_AREAS = {
|
|
|
324
474
|
# https://www.cosmos.esa.int/web/xmm-newton/technical-details-mirrors
|
|
325
475
|
"xmm": 1500 * u.cm**2,
|
|
326
476
|
"xmm slew": 1500 * u.cm**2,
|
|
477
|
+
"xmm-slew": 1500 * u.cm**2,
|
|
327
478
|
"xmm pointed": 1500 * u.cm**2,
|
|
479
|
+
"xmm-newton": 1500 * u.cm**2,
|
|
328
480
|
# https://cxc.harvard.edu/cdo/about_chandra
|
|
329
481
|
"chandra": 600 * u.cm**2,
|
|
482
|
+
# https://www.cosmos.esa.int/documents/332006/954765/Brunner_TopicK.pdf
|
|
483
|
+
"erosita": 1500 * u.cm**2,
|
|
330
484
|
}
|
|
331
485
|
"""
|
|
332
486
|
X-Ray telescope areas that are used for converting from counts to other units.
|
|
@@ -338,6 +492,45 @@ NOTE: These are estimates from the following links
|
|
|
338
492
|
* https://cxc.harvard.edu/cdo/about_chandra
|
|
339
493
|
"""
|
|
340
494
|
|
|
495
|
+
# Radio Band names with frequency ranges in GHz
|
|
496
|
+
RADIO_BAND_MAPPING = {
|
|
497
|
+
# use some lower bands from IEEE standards up to GMRT standards
|
|
498
|
+
# These are mostly here just as catchalls for low frequency radio telescopes
|
|
499
|
+
# like GEETEE or LOFAR
|
|
500
|
+
"HF": (0.003, 0.03),
|
|
501
|
+
"VHF": (0.03, 0.125), # Official: (0.03, 0.3) but adjust to work with GMRT standard
|
|
502
|
+
# use GMRT standards for low frequencies
|
|
503
|
+
"gmrt.2": (0.125, 0.250),
|
|
504
|
+
"gmrt.3": (0.25, 0.55), # Official: (0.25, 0.5)
|
|
505
|
+
# IEEE Standard Naming
|
|
506
|
+
# https://terasense.com/terahertz-technology/radio-frequency-bands/
|
|
507
|
+
"UHF": (0.55, 1),
|
|
508
|
+
"L": (1, 2),
|
|
509
|
+
"S": (2, 4),
|
|
510
|
+
"C": (4, 8),
|
|
511
|
+
"X": (8, 12),
|
|
512
|
+
"Ku": (12, 18),
|
|
513
|
+
"K": (18, 27),
|
|
514
|
+
"Ka": (27, 40),
|
|
515
|
+
# then switch to ALMA standard for mm
|
|
516
|
+
# https://www.eso.org/public/teles-instr/alma/receiver-bands/
|
|
517
|
+
# I widened some of the official ranges slightly so we don't leave gaps
|
|
518
|
+
# although these gaps probably wouldn't have mattered because **atmosphere**
|
|
519
|
+
"alma.1": (40, 50), # Official: (35, 50)
|
|
520
|
+
"alma.3": (84, 116), # skip alma.2 cause it's just a smaller range of alma.3
|
|
521
|
+
"alma.4": (116, 163), # official: (125, 163)
|
|
522
|
+
"alma.5": (163, 211),
|
|
523
|
+
"alma.6": (211, 275),
|
|
524
|
+
"alma.7": (275, 373),
|
|
525
|
+
"alma.8": (373, 500), # official: (385,500)
|
|
526
|
+
"alma.9": (500, 720), # official: (602, 720)
|
|
527
|
+
"alma.10": (787, 950),
|
|
528
|
+
}
|
|
529
|
+
"""
|
|
530
|
+
Mapping of common radio/mm band names to their corresponding frequency ranges.
|
|
531
|
+
All frequencies are in GHz. The upperlimit is inclusive, that is these ranges
|
|
532
|
+
are really (xx, yy].
|
|
533
|
+
"""
|
|
341
534
|
|
|
342
535
|
# define a working base directory constant
|
|
343
536
|
BASEDIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
@@ -345,11 +538,59 @@ BASEDIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file
|
|
|
345
538
|
Base directory for the OTTER API software package
|
|
346
539
|
"""
|
|
347
540
|
|
|
541
|
+
VIZIER_LARGE_CATALOGS = [
|
|
542
|
+
"2MASS-PSC",
|
|
543
|
+
"2MASX",
|
|
544
|
+
"AC2000.2",
|
|
545
|
+
"AKARI",
|
|
546
|
+
"ALLWISE",
|
|
547
|
+
"ASCC-2.5",
|
|
548
|
+
"B/DENIS",
|
|
549
|
+
"CMC14",
|
|
550
|
+
"Gaia-DR1",
|
|
551
|
+
"GALEX",
|
|
552
|
+
"GLIMPSE",
|
|
553
|
+
"GSC-ACT",
|
|
554
|
+
"GSC1.2",
|
|
555
|
+
"GSC2.2",
|
|
556
|
+
"GSC2.3",
|
|
557
|
+
"HIP",
|
|
558
|
+
"HIP2",
|
|
559
|
+
"IRAS",
|
|
560
|
+
"NOMAD1",
|
|
561
|
+
"NVSS",
|
|
562
|
+
"PanSTARRS-DR1",
|
|
563
|
+
"PGC",
|
|
564
|
+
"Planck-DR1",
|
|
565
|
+
"PPMX",
|
|
566
|
+
"PPMXL",
|
|
567
|
+
"SDSS-DR12",
|
|
568
|
+
"SDSS-DR7",
|
|
569
|
+
"SDSS-DR9",
|
|
570
|
+
"Tycho-2",
|
|
571
|
+
"UCAC2",
|
|
572
|
+
"UCAC3",
|
|
573
|
+
"UCAC4",
|
|
574
|
+
"UKIDSS",
|
|
575
|
+
"USNO-A2",
|
|
576
|
+
"USNO-B1",
|
|
577
|
+
"WISE",
|
|
578
|
+
]
|
|
579
|
+
"""
|
|
580
|
+
ViZier catalog names that we query for host information in the Host class
|
|
581
|
+
"""
|
|
582
|
+
|
|
348
583
|
DATADIR = os.path.join(BASEDIR, "data", "base")
|
|
349
584
|
"""
|
|
350
585
|
Deprecated database directory that IS NOT always constant anymore
|
|
351
586
|
"""
|
|
352
587
|
|
|
588
|
+
####################################################################
|
|
589
|
+
# The following schema dictionaries are here so the code remains
|
|
590
|
+
# backwards compatible. BUT! All future code should use the pydantic
|
|
591
|
+
# schema defined in schema.py
|
|
592
|
+
####################################################################
|
|
593
|
+
|
|
353
594
|
# Overarching schema that stops once we get down to a string or list
|
|
354
595
|
schema = {
|
|
355
596
|
"schema_version": {"value": "0", "comment": "Copied from tde.space"},
|
|
@@ -567,45 +808,3 @@ subschema = {
|
|
|
567
808
|
"""
|
|
568
809
|
A useful variable to describe all of the subschemas that are available and can be used
|
|
569
810
|
"""
|
|
570
|
-
|
|
571
|
-
VIZIER_LARGE_CATALOGS = [
|
|
572
|
-
"2MASS-PSC",
|
|
573
|
-
"2MASX",
|
|
574
|
-
"AC2000.2",
|
|
575
|
-
"AKARI",
|
|
576
|
-
"ALLWISE",
|
|
577
|
-
"ASCC-2.5",
|
|
578
|
-
"B/DENIS",
|
|
579
|
-
"CMC14",
|
|
580
|
-
"Gaia-DR1",
|
|
581
|
-
"GALEX",
|
|
582
|
-
"GLIMPSE",
|
|
583
|
-
"GSC-ACT",
|
|
584
|
-
"GSC1.2",
|
|
585
|
-
"GSC2.2",
|
|
586
|
-
"GSC2.3",
|
|
587
|
-
"HIP",
|
|
588
|
-
"HIP2",
|
|
589
|
-
"IRAS",
|
|
590
|
-
"NOMAD1",
|
|
591
|
-
"NVSS",
|
|
592
|
-
"PanSTARRS-DR1",
|
|
593
|
-
"PGC",
|
|
594
|
-
"Planck-DR1",
|
|
595
|
-
"PPMX",
|
|
596
|
-
"PPMXL",
|
|
597
|
-
"SDSS-DR12",
|
|
598
|
-
"SDSS-DR7",
|
|
599
|
-
"SDSS-DR9",
|
|
600
|
-
"Tycho-2",
|
|
601
|
-
"UCAC2",
|
|
602
|
-
"UCAC3",
|
|
603
|
-
"UCAC4",
|
|
604
|
-
"UKIDSS",
|
|
605
|
-
"USNO-A2",
|
|
606
|
-
"USNO-B1",
|
|
607
|
-
"WISE",
|
|
608
|
-
]
|
|
609
|
-
"""
|
|
610
|
-
ViZier catalog names that we query for host information in the Host class
|
|
611
|
-
"""
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
otter/__init__.py,sha256=ml7fLtTVno4fvpJvw91bAp8ff2nuRG1hZ1lMCt3ZumY,440
|
|
2
|
-
otter/_version.py,sha256=IwGQL03Wwse3OmpK33wS6CFwrF8rqxvbN79PydSE480,76
|
|
3
|
-
otter/exceptions.py,sha256=3lQF4AXVTfs9VRsVePQoIrXnramsPZbUL5crvf1s9Ng,1702
|
|
4
|
-
otter/util.py,sha256=7ZJYeTjBmwpXKgqXcmBtxhtn2j7XSQMaBbTurPKyEO0,15788
|
|
5
|
-
otter/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
otter/io/data_finder.py,sha256=pBGtfzjFt9pbJQR4exXP17eZoHVHClm_Jno1vXmcpAU,28026
|
|
7
|
-
otter/io/host.py,sha256=ZYewz347_6FD5mVcQLDxHSS75n5RCv69xxLHAmpjoiI,4410
|
|
8
|
-
otter/io/otter.py,sha256=VMtDCfiQniQNLIOL_P3NySwS-YnDF-nT4ceQjV0XJfE,18016
|
|
9
|
-
otter/io/transient.py,sha256=YVOppPAqhChPx8sxRPfuC_9BBJVtE7ku5ITKkWKSL9w,35551
|
|
10
|
-
otter/plotter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
otter/plotter/otter_plotter.py,sha256=iQe5AFsB5plw5eClUfuEfqcNRiXEcKc5-hkLPVKCkg8,2091
|
|
12
|
-
otter/plotter/plotter.py,sha256=i9ZAlbIjftpzyFzgCIFdye9XnppTwOSwazb5ruLpjnE,2896
|
|
13
|
-
astro_otter-0.1.0.dist-info/LICENSE,sha256=s9IPE8A3CAMEaZpDhj4eaorpmfLYGB0mIGphq301PUY,1067
|
|
14
|
-
astro_otter-0.1.0.dist-info/METADATA,sha256=nR8WxIF2Yez-yZxyv0kMZ-QZHuJJdcClr--J9cvbqHw,5905
|
|
15
|
-
astro_otter-0.1.0.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
|
|
16
|
-
astro_otter-0.1.0.dist-info/top_level.txt,sha256=Wth72sCwBRUk3KZGknSKvLQDMFuJk6qiaAavMDOdG5k,6
|
|
17
|
-
astro_otter-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|