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/io/host.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Host object that stores information on the Transient Host and provides utility methods
|
|
3
|
+
for pulling in data corresponding to that host
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from urllib.request import urlopen
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from astropy.coordinates import SkyCoord
|
|
13
|
+
from astropy import units as u
|
|
14
|
+
|
|
15
|
+
from .data_finder import DataFinder
|
|
16
|
+
from ..exceptions import OtterLimitationError
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Host(DataFinder):
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
host_ra: str | float,
|
|
27
|
+
host_dec: str | float,
|
|
28
|
+
host_ra_units: str | u.Unit,
|
|
29
|
+
host_dec_units: str | u.Unit,
|
|
30
|
+
host_name: str = None,
|
|
31
|
+
host_redshift: float = None,
|
|
32
|
+
redshift_type: str = None,
|
|
33
|
+
reference: list[str] = None,
|
|
34
|
+
transient_name: str = None,
|
|
35
|
+
**kwargs,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Object to store host information and query public data sources of host galaxies
|
|
39
|
+
|
|
40
|
+
Subclass of the data scraper class to allow for these queries to happen
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
host_ra (str|float) : The RA of the host to be passed to an astropy SkyCoord
|
|
44
|
+
host_dec (str|float) : The declination of the host to be passed to an
|
|
45
|
+
astropy SkyCoord
|
|
46
|
+
host_ra_units (str|astropy.units.Unit) : units of the RA, to be passed to
|
|
47
|
+
the unit keyword of SkyCoord
|
|
48
|
+
host_dec_units (str|astropy.units.Unit) : units of the declination, to be
|
|
49
|
+
passed to the unit keyword of
|
|
50
|
+
SkyCoord
|
|
51
|
+
host_name (str) : The name of the host galaxy
|
|
52
|
+
host_redshift (float) : The redshift of the host galaxy
|
|
53
|
+
redshift_type (str) : Either "phot" or "spec", tells you if the redshift
|
|
54
|
+
is a phot-z or spec-z.
|
|
55
|
+
reference (list[str]) : a list of bibcodes that found this to be the host
|
|
56
|
+
transient_name (str) : the name of the transient associated with this host
|
|
57
|
+
kwargs : Just here so we can pass **Transient['host'] into this constructor
|
|
58
|
+
and any extraneous properties will be ignored.
|
|
59
|
+
"""
|
|
60
|
+
self.coord = SkyCoord(host_ra, host_dec, unit=(host_ra_units, host_dec_units))
|
|
61
|
+
self.name = host_name
|
|
62
|
+
self.z = host_redshift
|
|
63
|
+
self.redshift = host_redshift # just here for ease of use
|
|
64
|
+
self.bibcodes = reference
|
|
65
|
+
self.transient_name = transient_name
|
|
66
|
+
self.redshift_type = redshift_type
|
|
67
|
+
|
|
68
|
+
def pcc(self, transient_coord: SkyCoord, mag: float = None):
|
|
69
|
+
"""
|
|
70
|
+
Compute the Probability of Chance Coincindence as described in
|
|
71
|
+
Bloom et al. (2002) "Offset Distribution of Gamma-Ray Bursts.
|
|
72
|
+
|
|
73
|
+
This computes the probability that this galaxy is by chance nearby to the
|
|
74
|
+
transient on the sky. Or, in simpler terms this essentially computes the
|
|
75
|
+
probability that we are wrong about this being the transient host. So, a
|
|
76
|
+
smaller probability is better!
|
|
77
|
+
|
|
78
|
+
Note: This probability was initially defined for GRB afterglows, which tend to
|
|
79
|
+
be redder transients (supernova too). So, be cautious when using this algorithm
|
|
80
|
+
for TDEs!
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
transient_coord (astropy.coordinates.SkyCoord) : The coordinates of the
|
|
84
|
+
transient object.
|
|
85
|
+
mag (float) : An r-band magnitude to compute from. Default is None which
|
|
86
|
+
will prompt us to check SDSS for one within 10".
|
|
87
|
+
Returns:
|
|
88
|
+
A float probability in the range [0,1]
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
# first get the separation r, in arcseconds
|
|
92
|
+
r = self.coord.separation(transient_coord).arcsec
|
|
93
|
+
|
|
94
|
+
# next get the host r magnitude
|
|
95
|
+
if mag is None:
|
|
96
|
+
res = self.query_vizier(radius=10 * u.arcsec)
|
|
97
|
+
|
|
98
|
+
if len(res) == 0:
|
|
99
|
+
raise OtterLimitationError(
|
|
100
|
+
"No magnitude found in SDSS! Please provide a magnitude via the \
|
|
101
|
+
`mag` keyword to make this calculation!"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
sdss = [k for k in res.keys() if "sdss" in k]
|
|
105
|
+
use = max(sdss, key=lambda k: int(k.split("sdss")[-1]))
|
|
106
|
+
print(f"Using the r magnitude from the {use} table")
|
|
107
|
+
mag = res[use]["rmag"][0]
|
|
108
|
+
|
|
109
|
+
# then compute the probability
|
|
110
|
+
sigma_prefactor = 1 / (3600**2 * 0.334 * np.log(10))
|
|
111
|
+
sigma_pow = 0.334 * (mag - 22.963) + 4.320
|
|
112
|
+
sigma = sigma_prefactor * 10**sigma_pow
|
|
113
|
+
|
|
114
|
+
eta = np.pi * r**2 * sigma
|
|
115
|
+
|
|
116
|
+
prob = 1 - np.exp(-eta)
|
|
117
|
+
|
|
118
|
+
return prob
|
|
119
|
+
|
|
120
|
+
###################################################################################
|
|
121
|
+
######### METHODS FOR FINDING HOSTS ###########################
|
|
122
|
+
###################################################################################
|
|
123
|
+
@staticmethod
|
|
124
|
+
def query_blast(tns_name: str) -> dict:
|
|
125
|
+
"""
|
|
126
|
+
Query the BLAST host galaxy service
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
tns_name (str) : The TNS target name to grab the data from BLAST for
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
best match BLAST ID, host ra, host dec, host redshift. Redshift will be
|
|
133
|
+
spectroscopic if available, otherwise photometric.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
# clean up the input name a little
|
|
137
|
+
if tns_name[:2] == "AT":
|
|
138
|
+
tns_name = tns_name.replace("AT", "")
|
|
139
|
+
|
|
140
|
+
failed_query_res = None
|
|
141
|
+
|
|
142
|
+
# do the query
|
|
143
|
+
blast_base_url = "https://blast.scimma.org"
|
|
144
|
+
blast_query_url = f"{blast_base_url}/api/transient/?name={tns_name}&format=json"
|
|
145
|
+
with urlopen(blast_query_url) as response:
|
|
146
|
+
if response.status != 200:
|
|
147
|
+
logger.warn(f"BLAST query failed with response code {response.status}!")
|
|
148
|
+
return failed_query_res
|
|
149
|
+
else:
|
|
150
|
+
blast_data = json.loads(response.read())
|
|
151
|
+
if len(blast_data) == 0:
|
|
152
|
+
logger.warn("BLAST query returned no results!")
|
|
153
|
+
return failed_query_res
|
|
154
|
+
|
|
155
|
+
blast_data = blast_data[0]
|
|
156
|
+
if "host" not in blast_data:
|
|
157
|
+
logger.warn("BLAST query found the object but it has no host associated!")
|
|
158
|
+
return failed_query_res
|
|
159
|
+
|
|
160
|
+
blast_host = blast_data["host"]
|
|
161
|
+
|
|
162
|
+
if blast_host["redshift"] is not None:
|
|
163
|
+
# prefer spec-z over phot-z
|
|
164
|
+
z = blast_host["redshift"]
|
|
165
|
+
z_type = "spec"
|
|
166
|
+
else:
|
|
167
|
+
# well I guess we need to use phot-z
|
|
168
|
+
z = blast_host["photometric_redshift"]
|
|
169
|
+
z_type = "phot"
|
|
170
|
+
|
|
171
|
+
refs = [
|
|
172
|
+
"2021ApJ...908..170G", # GHOST citation
|
|
173
|
+
"2024arXiv241017322J", # BLAST citation
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
return Host(
|
|
177
|
+
host_ra=blast_host["ra_deg"],
|
|
178
|
+
host_dec=blast_host["dec_deg"],
|
|
179
|
+
host_ra_units="deg",
|
|
180
|
+
host_dec_units="deg",
|
|
181
|
+
host_name=blast_host["id"],
|
|
182
|
+
host_redshift=z,
|
|
183
|
+
redshift_type=z_type,
|
|
184
|
+
reference=refs,
|
|
185
|
+
transient_name=tns_name,
|
|
186
|
+
)
|