stdpipe 0.4.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.
- stdpipe/__init__.py +9 -0
- stdpipe/artefacts.py +370 -0
- stdpipe/astrometry.py +2001 -0
- stdpipe/astrometry_quad.py +1643 -0
- stdpipe/astrometry_wcs.py +1141 -0
- stdpipe/catalogs.py +942 -0
- stdpipe/cutouts.py +570 -0
- stdpipe/data/legacysurvey_bricks.fits.gz +0 -0
- stdpipe/data/ps1skycells.txt +199708 -0
- stdpipe/db.py +130 -0
- stdpipe/fringe_removal.py +1086 -0
- stdpipe/lcs.py +440 -0
- stdpipe/photometry.py +2340 -0
- stdpipe/photometry_background.py +998 -0
- stdpipe/photometry_iraf.py +913 -0
- stdpipe/photometry_measure.py +2268 -0
- stdpipe/photometry_model.py +931 -0
- stdpipe/photometry_psf.py +1124 -0
- stdpipe/photometry_quality.py +185 -0
- stdpipe/pipeline.py +1303 -0
- stdpipe/plots.py +1582 -0
- stdpipe/psf.py +1542 -0
- stdpipe/realbogus.py +971 -0
- stdpipe/realbogus_features.py +1657 -0
- stdpipe/reproject.py +943 -0
- stdpipe/resolve.py +267 -0
- stdpipe/sfft.py +1077 -0
- stdpipe/simulation.py +2131 -0
- stdpipe/smoothing.py +488 -0
- stdpipe/subtraction.py +1324 -0
- stdpipe/templates.py +929 -0
- stdpipe/utils.py +365 -0
- stdpipe-0.4.0.dist-info/METADATA +171 -0
- stdpipe-0.4.0.dist-info/RECORD +37 -0
- stdpipe-0.4.0.dist-info/WHEEL +5 -0
- stdpipe-0.4.0.dist-info/licenses/LICENSE.md +21 -0
- stdpipe-0.4.0.dist-info/top_level.txt +1 -0
stdpipe/catalogs.py
ADDED
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module containing the routines for handling various online catalogues.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os, posixpath, shutil, tempfile
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from astropy.table import Table, MaskedColumn, vstack
|
|
9
|
+
from astroquery.vizier import Vizier
|
|
10
|
+
from astroquery.xmatch import XMatch
|
|
11
|
+
from astroquery.imcce import Skybot
|
|
12
|
+
from astroquery.ipac.ned import Ned
|
|
13
|
+
from astropy.coordinates import SkyCoord
|
|
14
|
+
from astropy import units as u
|
|
15
|
+
from astropy.time import Time
|
|
16
|
+
|
|
17
|
+
from . import astrometry
|
|
18
|
+
|
|
19
|
+
catalogs = {
|
|
20
|
+
'ps1': {'vizier': 'II/349/ps1', 'name': 'PanSTARRS DR1'},
|
|
21
|
+
'gaiadr2': {'vizier': 'I/345/gaia2', 'name': 'Gaia DR2', 'extra': ['E(BR/RP)']},
|
|
22
|
+
'gaiaedr3': {'vizier': 'I/350/gaiaedr3', 'name': 'Gaia EDR3'},
|
|
23
|
+
'gaiadr3syn': {
|
|
24
|
+
'vizier': 'I/360/syntphot',
|
|
25
|
+
'name': 'Gaia DR3 synthetic photometry',
|
|
26
|
+
'extra': ['**', '_RAJ2000', '_DEJ2000'],
|
|
27
|
+
},
|
|
28
|
+
'usnob1': {'vizier': 'I/284/out', 'name': 'USNO-B1'},
|
|
29
|
+
'gsc': {'vizier': 'I/271/out', 'name': 'GSC 2.2'},
|
|
30
|
+
'skymapper': {
|
|
31
|
+
'vizier': 'II/379/smssdr4',
|
|
32
|
+
'name': 'SkyMapper DR4',
|
|
33
|
+
'extra': [
|
|
34
|
+
'_RAJ2000',
|
|
35
|
+
'_DEJ2000',
|
|
36
|
+
'e_uPSF',
|
|
37
|
+
'e_vPSF',
|
|
38
|
+
'e_gPSF',
|
|
39
|
+
'e_rPSF',
|
|
40
|
+
'e_iPSF',
|
|
41
|
+
'e_zPSF',
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
'vsx': {'vizier': 'B/vsx/vsx', 'name': 'AAVSO VSX'},
|
|
45
|
+
'apass': {'vizier': 'II/336/apass9', 'name': 'APASS DR9'},
|
|
46
|
+
'sdss': {
|
|
47
|
+
'vizier': 'V/154/sdss16',
|
|
48
|
+
'name': 'SDSS DR16',
|
|
49
|
+
'extra': ['_RAJ2000', '_DEJ2000'],
|
|
50
|
+
},
|
|
51
|
+
'atlas': {
|
|
52
|
+
'vizier': 'J/ApJ/867/105/refcat2',
|
|
53
|
+
'name': 'ATLAS-REFCAT2',
|
|
54
|
+
'extra': [
|
|
55
|
+
'_RAJ2000',
|
|
56
|
+
'_DEJ2000',
|
|
57
|
+
'e_Gmag',
|
|
58
|
+
'e_gmag',
|
|
59
|
+
'e_rmag',
|
|
60
|
+
'e_imag',
|
|
61
|
+
'e_zmag',
|
|
62
|
+
'e_Jmag',
|
|
63
|
+
'e_Kmag',
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
'2mass': {
|
|
67
|
+
'vizier': 'II/246/out',
|
|
68
|
+
'name': '2MASS PSC',
|
|
69
|
+
},
|
|
70
|
+
'vhs': {
|
|
71
|
+
'vizier': 'II/367/vhs_dr5',
|
|
72
|
+
'name': 'Vista Hemisphere Survey DR5',
|
|
73
|
+
'extra': [
|
|
74
|
+
'e_Jap3',
|
|
75
|
+
'e_Hap3',
|
|
76
|
+
'e_Ksap3',
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _detect_catalog_type(cat):
|
|
83
|
+
"""
|
|
84
|
+
Detect catalog type from column names.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
cat : astropy.table.Table
|
|
89
|
+
Catalog table to inspect
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
catalog_type : str or None
|
|
94
|
+
Detected catalog type ('ps1', 'gaiadr2', 'skymapper', 'apass',
|
|
95
|
+
'gaiadr3syn', 'sdss', '2mass', 'vhs') or None if cannot detect
|
|
96
|
+
"""
|
|
97
|
+
colnames = set(cat.colnames)
|
|
98
|
+
|
|
99
|
+
# Check most specific patterns first to avoid ambiguity
|
|
100
|
+
|
|
101
|
+
# Gaia DR3 synthetic photometry - has Fu, Fg, Fr, Fi, Fz flux columns
|
|
102
|
+
if {'Fu', 'Fg', 'Fr', 'Fi', 'Fz'}.issubset(colnames):
|
|
103
|
+
return 'gaiadr3syn'
|
|
104
|
+
|
|
105
|
+
# Gaia DR2 - has Gmag, BPmag, RPmag
|
|
106
|
+
if {'Gmag', 'BPmag', 'RPmag'}.issubset(colnames):
|
|
107
|
+
return 'gaiadr2'
|
|
108
|
+
|
|
109
|
+
# SkyMapper - has gPSF, rPSF, iPSF, zPSF (PSF suffix is distinctive)
|
|
110
|
+
if {'gPSF', 'rPSF', 'iPSF', 'zPSF'}.issubset(colnames):
|
|
111
|
+
return 'skymapper'
|
|
112
|
+
|
|
113
|
+
# APASS - has both SDSS-like (g_mag, r_mag, i_mag) AND Johnson (B_mag, V_mag)
|
|
114
|
+
if {'g_mag', 'r_mag', 'i_mag', 'B_mag', 'V_mag'}.issubset(colnames):
|
|
115
|
+
return 'apass'
|
|
116
|
+
|
|
117
|
+
# SDSS DR16 - has umag, gmag, rmag, imag, zmag (but NOT ymag)
|
|
118
|
+
# Need to distinguish from PS1 which also has gmag, rmag, imag, zmag
|
|
119
|
+
if {'umag', 'gmag', 'rmag', 'imag', 'zmag'}.issubset(colnames):
|
|
120
|
+
if 'ymag' not in colnames: # SDSS doesn't have y band
|
|
121
|
+
return 'sdss'
|
|
122
|
+
|
|
123
|
+
# Pan-STARRS or ATLAS - both have gmag, rmag, imag, zmag, ymag
|
|
124
|
+
# Cannot distinguish between them from columns alone (identical augmentation anyway)
|
|
125
|
+
if {'gmag', 'rmag', 'imag', 'zmag', 'ymag'}.issubset(colnames):
|
|
126
|
+
return 'ps1' # Could be 'atlas' too, but augmentation is identical
|
|
127
|
+
|
|
128
|
+
# 2MASS
|
|
129
|
+
if {'Jmag', 'Hmag', 'Kmag'}.issubset(colnames):
|
|
130
|
+
return '2mass'
|
|
131
|
+
|
|
132
|
+
# VHS
|
|
133
|
+
if {'Jap3', 'Hap3', 'Ksap3'}.issubset(colnames):
|
|
134
|
+
return 'vhs'
|
|
135
|
+
|
|
136
|
+
# Could not detect
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _augment_ps1(cat, verbose=False):
|
|
141
|
+
"""Augment Pan-STARRS DR1 or ATLAS-RefCat2 catalog with additional bands."""
|
|
142
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
143
|
+
try:
|
|
144
|
+
log("Augmenting the catalogue with Johnson-Cousins photometry using PS1 mags")
|
|
145
|
+
|
|
146
|
+
# Alternative PS1 transfromation from https://arxiv.org/pdf/1706.06147.pdf, Stetson, seems better with Landolt than official one
|
|
147
|
+
# cat['B'] = cat['gmag'] + 0.199 + 0.540*(cat['gmag'] - cat['rmag']) + 0.016*(cat['gmag'] - cat['rmag'])**2
|
|
148
|
+
# cat['V'] = cat['gmag'] - 0.020 - 0.498*(cat['gmag'] - cat['rmag']) - 0.008*(cat['gmag'] - cat['rmag'])**2
|
|
149
|
+
# cat['R'] = cat['rmag'] - 0.163 - 0.086*(cat['gmag'] - cat['rmag']) - 0.061*(cat['gmag'] - cat['rmag'])**2
|
|
150
|
+
# cat['I'] = cat['imag'] - 0.387 - 0.123*(cat['gmag'] - cat['rmag']) - 0.034*(cat['gmag'] - cat['rmag'])**2
|
|
151
|
+
|
|
152
|
+
# My own fit on Landolt+Stetson standards from https://arxiv.org/pdf/2205.06186.pdf
|
|
153
|
+
pB1, pB2 = (
|
|
154
|
+
[
|
|
155
|
+
0.10339527794499666,
|
|
156
|
+
-0.492149523946056,
|
|
157
|
+
1.2093816061394638,
|
|
158
|
+
0.061925048331498395,
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
-0.2571974580267897,
|
|
162
|
+
0.9211495207523038,
|
|
163
|
+
-0.8243222108864755,
|
|
164
|
+
0.0619250483314976,
|
|
165
|
+
],
|
|
166
|
+
)
|
|
167
|
+
pV1, pV2 = (
|
|
168
|
+
[
|
|
169
|
+
-0.011452922062676726,
|
|
170
|
+
-9.949308251868327e-05,
|
|
171
|
+
-0.4650511584366353,
|
|
172
|
+
-0.007076854914511554,
|
|
173
|
+
],
|
|
174
|
+
[
|
|
175
|
+
0.012749150754020416,
|
|
176
|
+
0.057554580469724864,
|
|
177
|
+
-0.09019328095355343,
|
|
178
|
+
-0.007076854914511329,
|
|
179
|
+
],
|
|
180
|
+
)
|
|
181
|
+
pR1, pR2 = (
|
|
182
|
+
[
|
|
183
|
+
0.004905242602502597,
|
|
184
|
+
-0.046545625824660514,
|
|
185
|
+
0.07830702317352654,
|
|
186
|
+
-0.08438139204305026,
|
|
187
|
+
],
|
|
188
|
+
[
|
|
189
|
+
-0.07782426914647306,
|
|
190
|
+
0.14090289318728444,
|
|
191
|
+
-0.3634922073369279,
|
|
192
|
+
-0.08438139204305031,
|
|
193
|
+
],
|
|
194
|
+
)
|
|
195
|
+
pI1, pI2 = (
|
|
196
|
+
[
|
|
197
|
+
-0.02239162647929074,
|
|
198
|
+
0.04401240100377888,
|
|
199
|
+
-0.038500349283596795,
|
|
200
|
+
-0.19509051168348646,
|
|
201
|
+
],
|
|
202
|
+
[
|
|
203
|
+
0.014586929059030904,
|
|
204
|
+
-0.025228407778416825,
|
|
205
|
+
-0.21476143248697746,
|
|
206
|
+
-0.19509051168348637,
|
|
207
|
+
],
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
cat['Bmag'] = (
|
|
211
|
+
cat['gmag']
|
|
212
|
+
+ np.polyval(pB1, cat['gmag'] - cat['rmag'])
|
|
213
|
+
+ np.polyval(pB2, cat['rmag'] - cat['imag'])
|
|
214
|
+
)
|
|
215
|
+
cat['Vmag'] = (
|
|
216
|
+
cat['gmag']
|
|
217
|
+
+ np.polyval(pV1, cat['gmag'] - cat['rmag'])
|
|
218
|
+
+ np.polyval(pV2, cat['rmag'] - cat['imag'])
|
|
219
|
+
)
|
|
220
|
+
cat['Rmag'] = (
|
|
221
|
+
cat['rmag']
|
|
222
|
+
+ np.polyval(pR1, cat['gmag'] - cat['rmag'])
|
|
223
|
+
+ np.polyval(pR2, cat['rmag'] - cat['imag'])
|
|
224
|
+
)
|
|
225
|
+
cat['Imag'] = (
|
|
226
|
+
cat['imag']
|
|
227
|
+
+ np.polyval(pI1, cat['gmag'] - cat['rmag'])
|
|
228
|
+
+ np.polyval(pI2, cat['rmag'] - cat['imag'])
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
cat['e_Bmag'] = cat['e_gmag']
|
|
232
|
+
cat['e_Vmag'] = cat['e_gmag']
|
|
233
|
+
cat['e_Rmag'] = cat['e_rmag']
|
|
234
|
+
cat['e_Imag'] = cat['e_imag']
|
|
235
|
+
|
|
236
|
+
# Copies of columns for convenience
|
|
237
|
+
for _ in ['B', 'V', 'R', 'I']:
|
|
238
|
+
cat[_] = cat[_ + 'mag']
|
|
239
|
+
|
|
240
|
+
cat['good'] = (cat['gmag'] - cat['rmag'] > -0.5) & (cat['gmag'] - cat['rmag'] < 2.5)
|
|
241
|
+
cat['good'] &= (cat['rmag'] - cat['imag'] > -0.5) & (cat['rmag'] - cat['imag'] < 2.0)
|
|
242
|
+
cat['good'] &= (cat['imag'] - cat['zmag'] > -0.5) & (cat['imag'] - cat['zmag'] < 1.0)
|
|
243
|
+
|
|
244
|
+
# to SDSS, zero points and color terms from https://arxiv.org/pdf/1203.0297.pdf
|
|
245
|
+
cat['g_SDSS'] = (
|
|
246
|
+
cat['gmag']
|
|
247
|
+
+ 0.013
|
|
248
|
+
+ 0.145 * (cat['gmag'] - cat['rmag'])
|
|
249
|
+
+ 0.019 * (cat['gmag'] - cat['rmag']) ** 2
|
|
250
|
+
)
|
|
251
|
+
cat['r_SDSS'] = (
|
|
252
|
+
cat['rmag']
|
|
253
|
+
- 0.001
|
|
254
|
+
+ 0.004 * (cat['gmag'] - cat['rmag'])
|
|
255
|
+
+ 0.007 * (cat['gmag'] - cat['rmag']) ** 2
|
|
256
|
+
)
|
|
257
|
+
cat['i_SDSS'] = (
|
|
258
|
+
cat['imag']
|
|
259
|
+
- 0.005
|
|
260
|
+
+ 0.011 * (cat['gmag'] - cat['rmag'])
|
|
261
|
+
+ 0.010 * (cat['gmag'] - cat['rmag']) ** 2
|
|
262
|
+
)
|
|
263
|
+
cat['z_SDSS'] = cat['zmag']
|
|
264
|
+
|
|
265
|
+
except KeyError as e:
|
|
266
|
+
log(f"Warning: Missing required column for PS1 augmentation: {e}")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _augment_gaiadr2(cat, verbose=False):
|
|
270
|
+
"""Augment Gaia DR2 catalog with additional bands."""
|
|
271
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
272
|
+
try:
|
|
273
|
+
log("Augmenting the catalogue with Johnson-Cousins photometry using Gaia DR2 mags")
|
|
274
|
+
|
|
275
|
+
# My simple Gaia DR2 to Johnson conversion based on Stetson standards
|
|
276
|
+
pB = [
|
|
277
|
+
-0.05927724559795761,
|
|
278
|
+
0.4224326324292696,
|
|
279
|
+
0.626219707920836,
|
|
280
|
+
-0.011211539139725953,
|
|
281
|
+
]
|
|
282
|
+
pV = [
|
|
283
|
+
0.0017624722901609662,
|
|
284
|
+
0.15671377090187089,
|
|
285
|
+
0.03123927839356175,
|
|
286
|
+
0.041448557506784556,
|
|
287
|
+
]
|
|
288
|
+
pR = [
|
|
289
|
+
0.02045449129406191,
|
|
290
|
+
0.054005149296716175,
|
|
291
|
+
-0.3135475489352255,
|
|
292
|
+
0.020545083667168156,
|
|
293
|
+
]
|
|
294
|
+
pI = [
|
|
295
|
+
0.005092289380850884,
|
|
296
|
+
0.07027022935721515,
|
|
297
|
+
-0.7025553064161775,
|
|
298
|
+
-0.02747532184796779,
|
|
299
|
+
]
|
|
300
|
+
|
|
301
|
+
pCB = [876.4047401692277, 5.114021693079334, -2.7332873314449326, 0]
|
|
302
|
+
pCV = [98.03049528983964, 20.582521666713028, 0.8690079603974803, 0]
|
|
303
|
+
pCR = [347.42190542330945, 39.42482430363565, 0.8626828845232541, 0]
|
|
304
|
+
pCI = [79.4028706486939, 9.176899238787003, -0.7826315256072135, 0]
|
|
305
|
+
|
|
306
|
+
g = cat['Gmag']
|
|
307
|
+
bp_rp = cat['BPmag'] - cat['RPmag']
|
|
308
|
+
|
|
309
|
+
# phot_bp_rp_excess_factor == E(BR/RP) == E_BR_RP_
|
|
310
|
+
Cstar = cat['E_BR_RP_'] - np.polyval(
|
|
311
|
+
[-0.00445024, 0.0570293, -0.02810592, 1.20477819], bp_rp
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# https://www.cosmos.esa.int/web/gaia/dr2-known-issues#PhotometrySystematicEffectsAndResponseCurves
|
|
315
|
+
gcorr = g.copy()
|
|
316
|
+
gcorr[(g > 2) & (g < 6)] = (
|
|
317
|
+
-0.047344
|
|
318
|
+
+ 1.16405 * g[(g > 2) & (g < 6)]
|
|
319
|
+
- 0.046799 * g[(g > 2) & (g < 6)] ** 2
|
|
320
|
+
+ 0.0035015 * g[(g > 2) & (g < 6)] ** 3
|
|
321
|
+
)
|
|
322
|
+
gcorr[(g > 6) & (g < 16)] = g[(g > 6) & (g < 16)] - 0.0032 * (g[(g > 6) & (g < 16)] - 6)
|
|
323
|
+
gcorr[g > 16] = g[g > 16] - 0.032
|
|
324
|
+
g = gcorr
|
|
325
|
+
|
|
326
|
+
cat['Bmag'] = g + np.polyval(pB, bp_rp) + np.polyval(pCB, Cstar)
|
|
327
|
+
cat['Vmag'] = g + np.polyval(pV, bp_rp) + np.polyval(pCV, Cstar)
|
|
328
|
+
cat['Rmag'] = g + np.polyval(pR, bp_rp) + np.polyval(pCR, Cstar)
|
|
329
|
+
cat['Imag'] = g + np.polyval(pI, bp_rp) + np.polyval(pCI, Cstar)
|
|
330
|
+
|
|
331
|
+
# Rough estimation of magnitude error, just from G band
|
|
332
|
+
for _ in ['B', 'V', 'R', 'I', 'g', 'r']:
|
|
333
|
+
cat['e_' + _ + 'mag'] = cat['e_Gmag']
|
|
334
|
+
|
|
335
|
+
# Copies of columns for convenience
|
|
336
|
+
for _ in ['B', 'V', 'R', 'I']:
|
|
337
|
+
cat[_] = cat[_ + 'mag']
|
|
338
|
+
|
|
339
|
+
# to PS1 - FIXME: there are some uncorrected color and magnitude trends!
|
|
340
|
+
cat['gmag'] = (
|
|
341
|
+
cat['Bmag']
|
|
342
|
+
- 0.108
|
|
343
|
+
- 0.485 * (cat['Bmag'] - cat['Vmag'])
|
|
344
|
+
- 0.032 * (cat['Bmag'] - cat['Vmag']) ** 2
|
|
345
|
+
)
|
|
346
|
+
cat['rmag'] = (
|
|
347
|
+
cat['Vmag']
|
|
348
|
+
+ 0.082
|
|
349
|
+
- 0.462 * (cat['Bmag'] - cat['Vmag'])
|
|
350
|
+
+ 0.041 * (cat['Bmag'] - cat['Vmag']) ** 2
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# to SDSS, from https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/chap_cu5pho/sec_cu5pho_calibr/ssec_cu5pho_PhotTransf.html
|
|
354
|
+
cat['g_SDSS'] = g - (0.13518 - 0.46245 * bp_rp - 0.25171 * bp_rp**2 + 0.021349 * bp_rp**3)
|
|
355
|
+
cat['r_SDSS'] = g - (-0.12879 + 0.24662 * bp_rp - 0.027464 * bp_rp**2 - 0.049465 * bp_rp**3)
|
|
356
|
+
cat['i_SDSS'] = g - (-0.29676 + 0.64728 * bp_rp - 0.10141 * bp_rp**2)
|
|
357
|
+
|
|
358
|
+
except KeyError as e:
|
|
359
|
+
log(f"Warning: Missing required column for Gaia DR2 augmentation: {e}")
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _augment_skymapper(cat, verbose=False):
|
|
363
|
+
"""Augment SkyMapper DR4 catalog with additional bands."""
|
|
364
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
365
|
+
try:
|
|
366
|
+
log("Augmenting the catalogue with Pan-STARRS photometry using SkyMapper DR4 mags")
|
|
367
|
+
|
|
368
|
+
# SkyMapper DR4 to PS1 griz, my fit based on Pancino et al. (2022)
|
|
369
|
+
pg1, pg2 = (
|
|
370
|
+
[-0.07715320986152466, 0.2694597282089696, 0.04069379065128178, 0.01396290714542747],
|
|
371
|
+
[0.026097008342026252, -0.14040957287568073, 0.133647539780504, 0.013962907145427432],
|
|
372
|
+
)
|
|
373
|
+
pr1, pr2 = (
|
|
374
|
+
[0.08779280979185472, -0.23257704629617004, 0.1890698144343673, -0.008125550119663026],
|
|
375
|
+
[-0.06273832689338121, 0.21909317812693613, -0.23340488268623696, -0.00812555011966309],
|
|
376
|
+
)
|
|
377
|
+
pi1, pi2 = (
|
|
378
|
+
[
|
|
379
|
+
0.03553380678975111,
|
|
380
|
+
-0.021174189684500792,
|
|
381
|
+
-0.028159666883815007,
|
|
382
|
+
0.0009748746568893062,
|
|
383
|
+
],
|
|
384
|
+
[0.00911922467970264, -0.0362286983251751, 0.1403094994141109, 0.0009748746568892609],
|
|
385
|
+
)
|
|
386
|
+
pz1, pz2 = (
|
|
387
|
+
[
|
|
388
|
+
0.08071260245520126,
|
|
389
|
+
-0.051693023216670575,
|
|
390
|
+
-0.0739439627982131,
|
|
391
|
+
-0.0020460270205769223,
|
|
392
|
+
],
|
|
393
|
+
[
|
|
394
|
+
0.09720715174271254,
|
|
395
|
+
-0.32063637962189184,
|
|
396
|
+
0.37918283208242526,
|
|
397
|
+
-0.0020460270205769305,
|
|
398
|
+
],
|
|
399
|
+
)
|
|
400
|
+
py1, py2 = (
|
|
401
|
+
[0.038781034592287725, -0.11040188064275973, 0.08235396198116865, 0.006980454415779221],
|
|
402
|
+
[-0.0649739656901001, 0.205320995228645, -0.28233276303592, 0.006980454415779424],
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
cat['gmag'] = (
|
|
406
|
+
cat['gPSF']
|
|
407
|
+
+ np.polyval(pg1, cat['gPSF'] - cat['rPSF'])
|
|
408
|
+
+ np.polyval(pg2, cat['rPSF'] - cat['iPSF'])
|
|
409
|
+
)
|
|
410
|
+
cat['rmag'] = (
|
|
411
|
+
cat['rPSF']
|
|
412
|
+
+ np.polyval(pr1, cat['gPSF'] - cat['rPSF'])
|
|
413
|
+
+ np.polyval(pr2, cat['rPSF'] - cat['iPSF'])
|
|
414
|
+
)
|
|
415
|
+
cat['imag'] = (
|
|
416
|
+
cat['iPSF']
|
|
417
|
+
+ np.polyval(pi1, cat['gPSF'] - cat['rPSF'])
|
|
418
|
+
+ np.polyval(pi2, cat['rPSF'] - cat['iPSF'])
|
|
419
|
+
)
|
|
420
|
+
cat['zmag'] = (
|
|
421
|
+
cat['zPSF']
|
|
422
|
+
+ np.polyval(pz1, cat['gPSF'] - cat['rPSF'])
|
|
423
|
+
+ np.polyval(pz2, cat['rPSF'] - cat['iPSF'])
|
|
424
|
+
)
|
|
425
|
+
cat['ymag'] = (
|
|
426
|
+
cat['zPSF']
|
|
427
|
+
+ np.polyval(py1, cat['gPSF'] - cat['rPSF'])
|
|
428
|
+
+ np.polyval(py2, cat['rPSF'] - cat['iPSF'])
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
for _ in ['g', 'r', 'i', 'z']:
|
|
432
|
+
cat['e_' + _ + 'mag'] = cat['e_' + _ + 'PSF']
|
|
433
|
+
cat['e_ymag'] = cat['e_zPSF']
|
|
434
|
+
|
|
435
|
+
log("Augmenting the catalogue with Johnson-Cousins photometry using SkyMapper DR4 mags")
|
|
436
|
+
|
|
437
|
+
# SkyMapper DR4 to Johnson-Cousins BVRI, my fit based on Pancino et al. (2022)
|
|
438
|
+
pB1, pB2 = (
|
|
439
|
+
[-0.22773918482205113, 0.1818124624962873, 1.0021365492384895, 0.10762635377473588],
|
|
440
|
+
[-0.004034933919297649, 0.08214592357213418, -0.07535454054888649, 0.10762635377473558],
|
|
441
|
+
)
|
|
442
|
+
pV1, pV2 = (
|
|
443
|
+
[
|
|
444
|
+
-0.02545732895304914,
|
|
445
|
+
0.03256423830249228,
|
|
446
|
+
-0.33074199873567045,
|
|
447
|
+
-0.002938730214382037,
|
|
448
|
+
],
|
|
449
|
+
[-0.007342074336918033, 0.08255055271047995, -0.14349325478829064, -0.0029387302143822],
|
|
450
|
+
)
|
|
451
|
+
pR1, pR2 = (
|
|
452
|
+
[0.07296699439306827, -0.1943702618426095, 0.15375263988851387, -0.08547735652048871],
|
|
453
|
+
[-0.07378125129406726, 0.18462924970775316, -0.40720945890364135, -0.08547735652048903],
|
|
454
|
+
)
|
|
455
|
+
pI1, pI2 = (
|
|
456
|
+
[
|
|
457
|
+
-0.00925391710305653,
|
|
458
|
+
0.046223960182760516,
|
|
459
|
+
-0.06889215990613289,
|
|
460
|
+
-0.19321699685334734,
|
|
461
|
+
],
|
|
462
|
+
[
|
|
463
|
+
0.01197866152020802,
|
|
464
|
+
-0.044370062623186206,
|
|
465
|
+
-0.05231484699406009,
|
|
466
|
+
-0.19321699685334745,
|
|
467
|
+
],
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
cat['Bmag'] = (
|
|
471
|
+
cat['gPSF']
|
|
472
|
+
+ np.polyval(pB1, cat['gPSF'] - cat['rPSF'])
|
|
473
|
+
+ np.polyval(pB2, cat['rPSF'] - cat['iPSF'])
|
|
474
|
+
)
|
|
475
|
+
cat['Vmag'] = (
|
|
476
|
+
cat['gPSF']
|
|
477
|
+
+ np.polyval(pV1, cat['gPSF'] - cat['rPSF'])
|
|
478
|
+
+ np.polyval(pV2, cat['rPSF'] - cat['iPSF'])
|
|
479
|
+
)
|
|
480
|
+
cat['Rmag'] = (
|
|
481
|
+
cat['rPSF']
|
|
482
|
+
+ np.polyval(pR1, cat['gPSF'] - cat['rPSF'])
|
|
483
|
+
+ np.polyval(pR2, cat['rPSF'] - cat['iPSF'])
|
|
484
|
+
)
|
|
485
|
+
cat['Imag'] = (
|
|
486
|
+
cat['iPSF']
|
|
487
|
+
+ np.polyval(pI1, cat['gPSF'] - cat['rPSF'])
|
|
488
|
+
+ np.polyval(pI2, cat['rPSF'] - cat['iPSF'])
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
cat['e_Bmag'] = cat['e_gmag']
|
|
492
|
+
cat['e_Vmag'] = cat['e_gmag']
|
|
493
|
+
cat['e_Rmag'] = cat['e_rmag']
|
|
494
|
+
cat['e_Imag'] = cat['e_imag']
|
|
495
|
+
|
|
496
|
+
# Copies of columns for convenience
|
|
497
|
+
for _ in ['B', 'V', 'R', 'I']:
|
|
498
|
+
cat[_] = cat[_ + 'mag']
|
|
499
|
+
|
|
500
|
+
except KeyError as e:
|
|
501
|
+
log(f"Warning: Missing required column for SkyMapper augmentation: {e}")
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def _augment_apass(cat, verbose=False):
|
|
505
|
+
"""Augment APASS DR9 catalog with additional bands."""
|
|
506
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
507
|
+
try:
|
|
508
|
+
log("Augmenting the catalogue with Cousins R and I using APASS mags")
|
|
509
|
+
|
|
510
|
+
# My own fit based on Landolt standards
|
|
511
|
+
cat['Rmag'] = (
|
|
512
|
+
cat['r_mag']
|
|
513
|
+
- 0.157
|
|
514
|
+
- 0.087 * (cat['g_mag'] - cat['r_mag'])
|
|
515
|
+
- 0.014 * (cat['g_mag'] - cat['r_mag']) ** 2
|
|
516
|
+
)
|
|
517
|
+
cat['e_Rmag'] = cat['e_r_mag']
|
|
518
|
+
|
|
519
|
+
cat['Imag'] = (
|
|
520
|
+
cat['i_mag']
|
|
521
|
+
- 0.354
|
|
522
|
+
- 0.118 * (cat['g_mag'] - cat['r_mag'])
|
|
523
|
+
- 0.004 * (cat['g_mag'] - cat['r_mag']) ** 2
|
|
524
|
+
)
|
|
525
|
+
cat['e_Imag'] = cat['e_i_mag']
|
|
526
|
+
|
|
527
|
+
# Copies of columns for convenience
|
|
528
|
+
for _ in ['B', 'V', 'R', 'I']:
|
|
529
|
+
cat[_] = cat[_ + 'mag']
|
|
530
|
+
|
|
531
|
+
except KeyError as e:
|
|
532
|
+
log(f"Warning: Missing required column for APASS augmentation: {e}")
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def _augment_gaiadr3syn(cat, verbose=False):
|
|
536
|
+
"""Augment Gaia DR3 Synthetic Photometry catalog with additional bands."""
|
|
537
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
538
|
+
try:
|
|
539
|
+
# Compute magnitude errors from flux errors
|
|
540
|
+
for name in ['U', 'B', 'V', 'R', 'I', 'u', 'g', 'r', 'i', 'z', 'y']:
|
|
541
|
+
cat['e_' + name + 'mag'] = 2.5 / np.log(10) * cat['e_F' + name] / cat['F' + name]
|
|
542
|
+
|
|
543
|
+
log("Converting the catalogue Sloan magnitudes to Pan-STARRS ones")
|
|
544
|
+
|
|
545
|
+
# umag, gmag, rmag, imag and zmag are Sloan ugriz magnitudes! Let's get PS1 ones instead
|
|
546
|
+
# Fits are based on clean Landolt sample from https://arxiv.org/pdf/2205.06186
|
|
547
|
+
pg = [-0.030414391501015867, -0.09960002492299584, -0.002910024005294562]
|
|
548
|
+
pr = [-0.009566553708653305, 0.014924591443344211, -0.003928147919030857]
|
|
549
|
+
pi = [-0.010802807724098494, 0.01124900218746879, 0.01274293783734852]
|
|
550
|
+
pz = [-0.0031896767661109523, 0.06537983414287968, 0.007695587806229381]
|
|
551
|
+
|
|
552
|
+
for _ in ['u', 'g', 'r', 'i', 'z']:
|
|
553
|
+
cat[_ + '_SDSS'] = cat[_ + 'mag']
|
|
554
|
+
|
|
555
|
+
cat['gmag'] = cat['g_SDSS'] + np.polyval(pg, cat['g_SDSS'] - cat['r_SDSS'])
|
|
556
|
+
cat['rmag'] = cat['r_SDSS'] + np.polyval(pr, cat['g_SDSS'] - cat['r_SDSS'])
|
|
557
|
+
cat['imag'] = cat['i_SDSS'] + np.polyval(pi, cat['g_SDSS'] - cat['r_SDSS'])
|
|
558
|
+
cat['zmag'] = cat['z_SDSS'] + np.polyval(pz, cat['g_SDSS'] - cat['r_SDSS'])
|
|
559
|
+
|
|
560
|
+
except KeyError as e:
|
|
561
|
+
log(f"Warning: Missing required column for Gaia DR3 synphot augmentation: {e}")
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _augment_sdss(cat, verbose=False):
|
|
565
|
+
"""Augment SDSS DR16 catalog with additional bands."""
|
|
566
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
567
|
+
try:
|
|
568
|
+
log("Converting the catalogue Sloan magnitudes to AB ones")
|
|
569
|
+
|
|
570
|
+
# Zero point biases from https://www.sdss4.org/dr16/algorithms/fluxcal/#SDSStoAB
|
|
571
|
+
cat['umag'] -= 0.04
|
|
572
|
+
cat['zmag'] += 0.02
|
|
573
|
+
|
|
574
|
+
for _ in ['u', 'g', 'r', 'i', 'z']:
|
|
575
|
+
cat[_ + '_SDSS'] = cat[_ + 'mag']
|
|
576
|
+
|
|
577
|
+
except KeyError as e:
|
|
578
|
+
log(f"Warning: Missing required column for SDSS augmentation: {e}")
|
|
579
|
+
|
|
580
|
+
def _augment_2mass(cat, verbose=False):
|
|
581
|
+
"""Augment 2MASS catalog with additional bands."""
|
|
582
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
583
|
+
try:
|
|
584
|
+
log("Renaming the catalogue K magnitudes to Ks ones")
|
|
585
|
+
|
|
586
|
+
cat['Ksmag'] = cat['Kmag']
|
|
587
|
+
cat['e_Ksmag'] = cat['e_Kmag']
|
|
588
|
+
|
|
589
|
+
except KeyError as e:
|
|
590
|
+
log(f"Warning: Missing required column for 2MASS augmentation: {e}")
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def _augment_vhs(cat, verbose=False):
|
|
594
|
+
"""Augment VHS catalog with 2MASS-system JHKs magnitudes."""
|
|
595
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
596
|
+
try:
|
|
597
|
+
log("Augmenting the catalogue with 2MASS magnitudes")
|
|
598
|
+
|
|
599
|
+
for _ in ['J', 'H', 'Ks']:
|
|
600
|
+
cat[f"{_}mag"] = cat[f"{_}ap3"]
|
|
601
|
+
cat[f"e_{_}mag"] = cat[f"e_{_}ap3"]
|
|
602
|
+
|
|
603
|
+
def color_term(a, b, coeff):
|
|
604
|
+
# Color-term correction that degrades gracefully to zero (i.e. keeps the
|
|
605
|
+
# uncorrected VISTA magnitude) where the auxiliary band is missing, so that
|
|
606
|
+
# e.g. a field lacking H-band coverage does not wipe out the J magnitudes.
|
|
607
|
+
term = coeff * (np.ma.filled(cat[a].astype(float), np.nan)
|
|
608
|
+
- np.ma.filled(cat[b].astype(float), np.nan))
|
|
609
|
+
n_bad = int(np.count_nonzero(np.isnan(term)))
|
|
610
|
+
if n_bad:
|
|
611
|
+
log(f"Warning: {n_bad}/{len(cat)} stars lack {a} or {b}; "
|
|
612
|
+
f"their magnitudes are left uncorrected for the {a}-{b} colour term")
|
|
613
|
+
return np.nan_to_num(term, nan=0.0)
|
|
614
|
+
|
|
615
|
+
# VISTA to 2MASS equations from https://ui.adsabs.harvard.edu/abs/2013A%26A...552A.101S
|
|
616
|
+
cat['Jmag'] += color_term('Jap3', 'Hap3', 0.070)
|
|
617
|
+
cat['Hmag'] += color_term('Hap3', 'Ksap3', -0.035)
|
|
618
|
+
cat['Ksmag'] += color_term('Jap3', 'Ksap3', -0.011)
|
|
619
|
+
|
|
620
|
+
except KeyError as e:
|
|
621
|
+
log(f"Warning: Missing required column for VHS augmentation: {e}")
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def augment_cat_bands(cat, catalog=None, verbose=False):
|
|
625
|
+
"""
|
|
626
|
+
Augment catalog with additional photometric bands via magnitude conversions.
|
|
627
|
+
|
|
628
|
+
Parameters
|
|
629
|
+
----------
|
|
630
|
+
cat : astropy.table.Table
|
|
631
|
+
Input catalog to augment. Modified in-place.
|
|
632
|
+
catalog : str, optional
|
|
633
|
+
Catalog type: 'ps1', 'atlas', 'gaiadr2', 'skymapper', 'apass',
|
|
634
|
+
'gaiadr3syn', 'sdss', '2mass', 'vhs'. If None, auto-detect from columns.
|
|
635
|
+
verbose : bool or callable, optional
|
|
636
|
+
Logging control.
|
|
637
|
+
|
|
638
|
+
Returns
|
|
639
|
+
-------
|
|
640
|
+
cat : astropy.table.Table
|
|
641
|
+
The input catalog with additional magnitude columns.
|
|
642
|
+
"""
|
|
643
|
+
# Setup logging
|
|
644
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
645
|
+
|
|
646
|
+
# Auto-detect if not specified
|
|
647
|
+
if catalog is None:
|
|
648
|
+
catalog = _detect_catalog_type(cat)
|
|
649
|
+
if catalog is None:
|
|
650
|
+
log("Warning: Could not detect catalog type. Skipping augmentation.")
|
|
651
|
+
return cat
|
|
652
|
+
log(f"Auto-detected catalog type: {catalog}")
|
|
653
|
+
|
|
654
|
+
# Dispatch to appropriate helper
|
|
655
|
+
if catalog == 'ps1' or catalog == 'atlas':
|
|
656
|
+
_augment_ps1(cat, verbose=verbose)
|
|
657
|
+
elif catalog == 'gaiadr2':
|
|
658
|
+
_augment_gaiadr2(cat, verbose=verbose)
|
|
659
|
+
elif catalog == 'skymapper':
|
|
660
|
+
_augment_skymapper(cat, verbose=verbose)
|
|
661
|
+
elif catalog == 'apass':
|
|
662
|
+
_augment_apass(cat, verbose=verbose)
|
|
663
|
+
elif catalog == 'gaiadr3syn':
|
|
664
|
+
_augment_gaiadr3syn(cat, verbose=verbose)
|
|
665
|
+
elif catalog == 'sdss':
|
|
666
|
+
_augment_sdss(cat, verbose=verbose)
|
|
667
|
+
elif catalog == '2mass':
|
|
668
|
+
_augment_2mass(cat, verbose=verbose)
|
|
669
|
+
elif catalog == 'vhs':
|
|
670
|
+
_augment_vhs(cat, verbose=verbose)
|
|
671
|
+
else:
|
|
672
|
+
log(f"Warning: Unknown catalog type '{catalog}'. Skipping augmentation.")
|
|
673
|
+
|
|
674
|
+
return cat
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
def get_cat_vizier(
|
|
678
|
+
ra0,
|
|
679
|
+
dec0,
|
|
680
|
+
sr0,
|
|
681
|
+
catalog='ps1',
|
|
682
|
+
limit=-1,
|
|
683
|
+
filters={},
|
|
684
|
+
extra=[],
|
|
685
|
+
get_distance=False,
|
|
686
|
+
augment_bands=True,
|
|
687
|
+
verbose=False,
|
|
688
|
+
):
|
|
689
|
+
"""Download any catalogue from Vizier.
|
|
690
|
+
|
|
691
|
+
The catalogue may be any Vizier identifier. For a number of popular catalogues,
|
|
692
|
+
additional photometric bands are computed from analytical conversion formulae:
|
|
693
|
+
|
|
694
|
+
- ``ps1`` — Pan-STARRS DR1, augmented with Johnson-Cousins B, V, R, I
|
|
695
|
+
- ``gaiadr2`` — Gaia DR2, augmented with Johnson-Cousins B, V, R, I, Pan-STARRS and SDSS
|
|
696
|
+
- ``gaiaedr3`` — Gaia eDR3
|
|
697
|
+
- ``gaiadr3syn`` — Gaia DR3 synthetic photometry from XP spectra
|
|
698
|
+
- ``skymapper`` — SkyMapper DR1.1
|
|
699
|
+
- ``vsx`` — AAVSO Variable Stars Index
|
|
700
|
+
- ``apass`` — AAVSO APASS DR9
|
|
701
|
+
- ``sdss`` — SDSS DR16
|
|
702
|
+
- ``atlas`` — ATLAS-RefCat2, augmented with Johnson-Cousins B, V, R, I
|
|
703
|
+
- ``usnob1`` — USNO-B1
|
|
704
|
+
- ``gsc`` — Guide Star Catalogue 2.2
|
|
705
|
+
- ``2mass`` — 2MASS Point Source Catalogue
|
|
706
|
+
- ``vhs`` — VISTA Hemisphere Survey DR5, augmented with 2MASS-system J, H, Ks
|
|
707
|
+
|
|
708
|
+
Parameters
|
|
709
|
+
----------
|
|
710
|
+
ra0 : float
|
|
711
|
+
Right Ascension of the field center in degrees.
|
|
712
|
+
dec0 : float
|
|
713
|
+
Declination of the field center in degrees.
|
|
714
|
+
sr0 : float
|
|
715
|
+
Field radius in degrees.
|
|
716
|
+
catalog : str, optional
|
|
717
|
+
Any Vizier catalogue identifier or a short name from the list above.
|
|
718
|
+
limit : int, optional
|
|
719
|
+
Maximum number of rows to return (``-1`` for unlimited).
|
|
720
|
+
filters : dict, optional
|
|
721
|
+
Column filters applied server-side. Keys are column names; values are
|
|
722
|
+
Vizier filter expressions.
|
|
723
|
+
extra : list of str, optional
|
|
724
|
+
Additional column names to include beyond the defaults.
|
|
725
|
+
get_distance : bool, optional
|
|
726
|
+
If True, include a ``_r`` column with angular distance from field center.
|
|
727
|
+
augment_bands : bool, optional
|
|
728
|
+
If True (default), augment photometry with derived bands where supported.
|
|
729
|
+
verbose : bool or callable, optional
|
|
730
|
+
Whether to show verbose messages. May be boolean or a ``print``-like callable.
|
|
731
|
+
|
|
732
|
+
Returns
|
|
733
|
+
-------
|
|
734
|
+
astropy.table.Table or None
|
|
735
|
+
Catalogue as returned by Vizier, with additional columns for supported
|
|
736
|
+
catalogues, or None if the query fails.
|
|
737
|
+
"""
|
|
738
|
+
|
|
739
|
+
# Simple Wrapper around print for logging in verbose mode only
|
|
740
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
741
|
+
|
|
742
|
+
# TODO: add positional errors
|
|
743
|
+
|
|
744
|
+
if catalog in catalogs:
|
|
745
|
+
# For some catalogs we may have some additional information
|
|
746
|
+
vizier_id = catalogs.get(catalog).get('vizier')
|
|
747
|
+
name = catalogs.get(catalog).get('name')
|
|
748
|
+
|
|
749
|
+
columns = (
|
|
750
|
+
['*', 'RAJ2000', 'DEJ2000', 'e_RAJ2000', 'e_DEJ2000']
|
|
751
|
+
+ extra
|
|
752
|
+
+ catalogs.get(catalog).get('extra', [])
|
|
753
|
+
)
|
|
754
|
+
else:
|
|
755
|
+
vizier_id = catalog
|
|
756
|
+
name = catalog
|
|
757
|
+
columns = ['*', 'RAJ2000', 'DEJ2000', 'e_RAJ2000', 'e_DEJ2000'] + extra
|
|
758
|
+
|
|
759
|
+
log('Requesting from VizieR:', vizier_id, 'columns:', columns)
|
|
760
|
+
log('Center: %.3f %.3f' % (ra0, dec0), 'radius: %.3f' % sr0)
|
|
761
|
+
log('Filters:', filters)
|
|
762
|
+
|
|
763
|
+
vizier = Vizier(row_limit=limit, columns=columns, column_filters=filters)
|
|
764
|
+
cats = vizier.query_region(
|
|
765
|
+
SkyCoord(ra0, dec0, unit='deg'), radius=sr0 * u.deg, catalog=vizier_id
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
if not cats or not len(cats) == 1:
|
|
769
|
+
cats = vizier.query_region(
|
|
770
|
+
SkyCoord(ra0, dec0, unit='deg'),
|
|
771
|
+
radius=sr0 * u.deg,
|
|
772
|
+
catalog=vizier_id,
|
|
773
|
+
cache=False,
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
if not cats or not len(cats) == 1:
|
|
777
|
+
log('Error requesting catalogue', catalog)
|
|
778
|
+
return None
|
|
779
|
+
|
|
780
|
+
cat = cats[0]
|
|
781
|
+
cat.meta['vizier_id'] = vizier_id
|
|
782
|
+
cat.meta['name'] = name
|
|
783
|
+
|
|
784
|
+
log('Got', len(cat), 'entries with', len(cat.colnames), 'columns')
|
|
785
|
+
|
|
786
|
+
# Fix _RAJ2000/_DEJ2000
|
|
787
|
+
if '_RAJ2000' in cat.keys() and '_DEJ2000' in cat.keys() and not 'RAJ2000' in cat.keys():
|
|
788
|
+
cat.rename_columns(['_RAJ2000', '_DEJ2000'], ['RAJ2000', 'DEJ2000'])
|
|
789
|
+
|
|
790
|
+
if get_distance and 'RAJ2000' in cat.colnames and 'DEJ2000' in cat.colnames:
|
|
791
|
+
log("Augmenting the catalogue with distances from field center")
|
|
792
|
+
cat['_r'] = astrometry.spherical_distance(ra0, dec0, cat['RAJ2000'], cat['DEJ2000'])
|
|
793
|
+
|
|
794
|
+
if augment_bands or True:
|
|
795
|
+
# Augment catalogue with additional bandpasses
|
|
796
|
+
augment_cat_bands(cat, catalog=catalog if catalog in catalogs else None, verbose=verbose)
|
|
797
|
+
|
|
798
|
+
return cat
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def xmatch_objects(obj, catalog='ps1', sr=3 / 3600, col_ra='ra', col_dec='dec', augment_bands=True):
|
|
802
|
+
"""Cross-match object list with a Vizier catalogue using the CDS XMatch service.
|
|
803
|
+
|
|
804
|
+
Parameters
|
|
805
|
+
----------
|
|
806
|
+
obj : astropy.table.Table
|
|
807
|
+
Table of objects to cross-match.
|
|
808
|
+
catalog : str, optional
|
|
809
|
+
Any Vizier catalogue identifier or a short name recognized by :func:`get_cat_vizier`.
|
|
810
|
+
sr : float, optional
|
|
811
|
+
Cross-matching radius in degrees.
|
|
812
|
+
col_ra : str, optional
|
|
813
|
+
Column name in ``obj`` containing Right Ascension values.
|
|
814
|
+
col_dec : str, optional
|
|
815
|
+
Column name in ``obj`` containing Declination values.
|
|
816
|
+
augment_bands : bool, optional
|
|
817
|
+
If True (default), augment photometry with derived bands where supported.
|
|
818
|
+
|
|
819
|
+
Returns
|
|
820
|
+
-------
|
|
821
|
+
astropy.table.Table
|
|
822
|
+
Table of matched objects augmented with columns from the Vizier catalogue.
|
|
823
|
+
"""
|
|
824
|
+
|
|
825
|
+
if catalog in catalogs:
|
|
826
|
+
vizier_id = catalogs.get(catalog)['vizier']
|
|
827
|
+
else:
|
|
828
|
+
vizier_id = catalog
|
|
829
|
+
|
|
830
|
+
xcat = XMatch().query(
|
|
831
|
+
cat1=obj,
|
|
832
|
+
cat2='vizier:' + vizier_id,
|
|
833
|
+
max_distance=sr * u.deg,
|
|
834
|
+
colRA1=col_ra,
|
|
835
|
+
colDec1=col_dec,
|
|
836
|
+
)
|
|
837
|
+
|
|
838
|
+
if augment_bands:
|
|
839
|
+
# Augment catalogue with additional bandpasses
|
|
840
|
+
augment_cat_bands(xcat, catalog=catalog if catalog in catalogs else None)
|
|
841
|
+
|
|
842
|
+
return xcat
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
def xmatch_skybot(obj, sr=10 / 3600, time=None, col_ra='ra', col_dec='dec', col_id='id'):
|
|
846
|
+
"""Cross-match object list with Solar System object positions using SkyBoT.
|
|
847
|
+
|
|
848
|
+
Queries SkyBoT for all Solar System objects in a cone covering the input
|
|
849
|
+
field at the specified time, then cross-matches them against the input list
|
|
850
|
+
within ``sr``.
|
|
851
|
+
|
|
852
|
+
Parameters
|
|
853
|
+
----------
|
|
854
|
+
obj : astropy.table.Table
|
|
855
|
+
Table of objects to cross-match.
|
|
856
|
+
sr : float, optional
|
|
857
|
+
Cross-matching radius in degrees.
|
|
858
|
+
time : astropy.time.Time or datetime or str
|
|
859
|
+
Observation time.
|
|
860
|
+
col_ra : str, optional
|
|
861
|
+
Column name in ``obj`` containing Right Ascension values.
|
|
862
|
+
col_dec : str, optional
|
|
863
|
+
Column name in ``obj`` containing Declination values.
|
|
864
|
+
col_id : str, optional
|
|
865
|
+
Column name in ``obj`` containing unique object identifiers.
|
|
866
|
+
|
|
867
|
+
Returns
|
|
868
|
+
-------
|
|
869
|
+
astropy.table.Table or None
|
|
870
|
+
Table of matched Solar System objects with a ``col_id`` column referencing
|
|
871
|
+
the matched input objects, or None if no matches are found.
|
|
872
|
+
"""
|
|
873
|
+
|
|
874
|
+
ra0, dec0, sr0 = astrometry.get_objects_center(obj)
|
|
875
|
+
|
|
876
|
+
try:
|
|
877
|
+
# Query SkyBot for (a bit larger than) our FOV at our time
|
|
878
|
+
xcat = Skybot.cone_search(
|
|
879
|
+
SkyCoord(ra0, dec0, unit='deg'), (sr0 + 2.0 * sr) * u.deg, Time(time)
|
|
880
|
+
)
|
|
881
|
+
except (RuntimeError, KeyError, ConnectionError, OSError):
|
|
882
|
+
# Nothing found in SkyBot
|
|
883
|
+
return None
|
|
884
|
+
|
|
885
|
+
if xcat is None or len(xcat) == 0:
|
|
886
|
+
return None
|
|
887
|
+
|
|
888
|
+
# Cross-match objects
|
|
889
|
+
oidx, cidx, dist = astrometry.spherical_match(
|
|
890
|
+
obj[col_ra], obj[col_dec], xcat['RA'], xcat['DEC'], 10 / 3600
|
|
891
|
+
)
|
|
892
|
+
|
|
893
|
+
# Annotate the table with id from objects so that it is possible to identify the matches
|
|
894
|
+
xcat[col_id] = MaskedColumn(len(xcat), dtype=np.dtype(obj[col_id][0]))
|
|
895
|
+
xcat[col_id].mask = True
|
|
896
|
+
xcat[col_id][cidx] = obj[col_id][oidx]
|
|
897
|
+
xcat[col_id][cidx].mask = False
|
|
898
|
+
|
|
899
|
+
return xcat
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
def xmatch_ned(obj, sr=3 / 3600, col_ra='ra', col_dec='dec', col_id='id'):
|
|
903
|
+
"""Cross-match object list with NED database entries.
|
|
904
|
+
|
|
905
|
+
.. note::
|
|
906
|
+
Queries NED one object at a time, so this is slow for large lists.
|
|
907
|
+
|
|
908
|
+
Parameters
|
|
909
|
+
----------
|
|
910
|
+
obj : astropy.table.Table
|
|
911
|
+
Table of objects to cross-match.
|
|
912
|
+
sr : float, optional
|
|
913
|
+
Cross-matching radius in degrees.
|
|
914
|
+
col_ra : str, optional
|
|
915
|
+
Column name in ``obj`` containing Right Ascension values.
|
|
916
|
+
col_dec : str, optional
|
|
917
|
+
Column name in ``obj`` containing Declination values.
|
|
918
|
+
col_id : str, optional
|
|
919
|
+
Column name in ``obj`` containing unique object identifiers.
|
|
920
|
+
|
|
921
|
+
Returns
|
|
922
|
+
-------
|
|
923
|
+
astropy.table.Table or list
|
|
924
|
+
Table of NED objects with an ``id`` column referencing the matched input
|
|
925
|
+
objects, or an empty list if no matches are found.
|
|
926
|
+
"""
|
|
927
|
+
|
|
928
|
+
xcat = []
|
|
929
|
+
|
|
930
|
+
# FIXME: is there more optimal way to query NED for multiple sky positions?..
|
|
931
|
+
for row in obj:
|
|
932
|
+
res = Ned().query_region(SkyCoord(row[col_ra], row[col_dec], unit='deg'), sr * u.deg)
|
|
933
|
+
|
|
934
|
+
if res:
|
|
935
|
+
res['id'] = row[col_id]
|
|
936
|
+
|
|
937
|
+
xcat.append(res)
|
|
938
|
+
|
|
939
|
+
if xcat:
|
|
940
|
+
xcat = vstack(xcat, join_type='exact', metadata_conflicts='silent')
|
|
941
|
+
|
|
942
|
+
return xcat
|