stdpipe 0.2.1__tar.gz → 0.2.2__tar.gz

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.
Files changed (32) hide show
  1. {stdpipe-0.2.1/stdpipe.egg-info → stdpipe-0.2.2}/PKG-INFO +1 -1
  2. {stdpipe-0.2.1 → stdpipe-0.2.2}/setup.py +1 -1
  3. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/cutouts.py +4 -0
  4. stdpipe-0.2.2/stdpipe/flycheck_catalogs.py +637 -0
  5. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/photometry.py +11 -12
  6. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/pipeline.py +1 -1
  7. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/plots.py +33 -16
  8. {stdpipe-0.2.1 → stdpipe-0.2.2/stdpipe.egg-info}/PKG-INFO +1 -1
  9. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe.egg-info/SOURCES.txt +1 -0
  10. {stdpipe-0.2.1 → stdpipe-0.2.2}/.gitignore +0 -0
  11. {stdpipe-0.2.1 → stdpipe-0.2.2}/LICENSE.md +0 -0
  12. {stdpipe-0.2.1 → stdpipe-0.2.2}/MANIFEST.in +0 -0
  13. {stdpipe-0.2.1 → stdpipe-0.2.2}/README.md +0 -0
  14. {stdpipe-0.2.1 → stdpipe-0.2.2}/setup.cfg +0 -0
  15. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/__init__.py +0 -0
  16. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/astrometry.py +0 -0
  17. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/catalogs.py +0 -0
  18. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/data/legacysurvey.py +0 -0
  19. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/data/legacysurvey_bricks.fits.gz +0 -0
  20. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/data/ps1skycells.txt +0 -0
  21. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/data/ps1skycells.txt.orig +0 -0
  22. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/db.py +0 -0
  23. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/lcs.py +0 -0
  24. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/psf.py +0 -0
  25. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/resolve.py +0 -0
  26. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/subtraction.py +0 -0
  27. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/templates.py +0 -0
  28. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe/utils.py +0 -0
  29. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe.egg-info/dependency_links.txt +0 -0
  30. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe.egg-info/requires.txt +0 -0
  31. {stdpipe-0.2.1 → stdpipe-0.2.2}/stdpipe.egg-info/top_level.txt +0 -0
  32. {stdpipe-0.2.1 → stdpipe-0.2.2}/tests/test_dependencies.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stdpipe
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Simple Transient Detection Pipeline
5
5
  Home-page: https://github.com/karpov-sv/stdpipe
6
6
  Author: Sergey Karpov
@@ -3,7 +3,7 @@
3
3
 
4
4
  from setuptools import setup, find_packages
5
5
 
6
- __version__ = '0.2.1'
6
+ __version__ = '0.2.2'
7
7
 
8
8
  requirements = [
9
9
  'numpy',
@@ -231,6 +231,8 @@ def write_cutout(cutout, filename):
231
231
  data = Time(data).to_value('fits')
232
232
  elif np.isreal(data) and np.isnan(data):
233
233
  data = 'NaN'
234
+ elif np.isreal(data) and not np.isfinite(data):
235
+ data = 'Inf'
234
236
 
235
237
  hdu.header[_] = data
236
238
 
@@ -301,6 +303,8 @@ def load_cutout(filename):
301
303
  data = Time(data)
302
304
  elif data == 'NaN':
303
305
  data = np.nan
306
+ elif data == 'Inf':
307
+ data = np.inf
304
308
 
305
309
  cutout['meta'][name] = data
306
310
 
@@ -0,0 +1,637 @@
1
+ """
2
+ Module containing the routines for handling various online catalogues.
3
+ """
4
+
5
+ from __future__ import absolute_import, division, print_function, unicode_literals
6
+
7
+ import os, posixpath, shutil, tempfile
8
+ import numpy as np
9
+
10
+ from astropy.table import Table, MaskedColumn, vstack
11
+ from astroquery.vizier import Vizier
12
+ from astroquery.xmatch import XMatch
13
+ from astroquery.imcce import Skybot
14
+ from astroquery.ned import Ned
15
+ from astropy.coordinates import SkyCoord
16
+ from astropy import units as u
17
+ from astropy.time import Time
18
+
19
+ from . import astrometry
20
+
21
+ catalogs = {
22
+ 'ps1': {'vizier': 'II/349/ps1', 'name': 'PanSTARRS DR1'},
23
+ 'gaiadr2': {'vizier': 'I/345/gaia2', 'name': 'Gaia DR2', 'extra': ['E(BR/RP)']},
24
+ 'gaiaedr3': {'vizier': 'I/350/gaiaedr3', 'name': 'Gaia EDR3'},
25
+ 'gaiadr3syn': {
26
+ 'vizier': 'I/360/syntphot',
27
+ 'name': 'Gaia DR3 synthetic photometry',
28
+ 'extra': ['**', '_RAJ2000', '_DEJ2000'],
29
+ },
30
+ 'usnob1': {'vizier': 'I/284/out', 'name': 'USNO-B1'},
31
+ 'gsc': {'vizier': 'I/271/out', 'name': 'GSC 2.2'},
32
+ 'skymapper': {
33
+ 'vizier': 'II/358/smss',
34
+ 'name': 'SkyMapper DR1.1',
35
+ 'extra': [
36
+ '_RAJ2000',
37
+ '_DEJ2000',
38
+ 'e_uPSF',
39
+ 'e_vPSF',
40
+ 'e_gPSF',
41
+ 'e_rPSF',
42
+ 'e_iPSF',
43
+ 'e_zPSF',
44
+ ],
45
+ },
46
+ 'vsx': {'vizier': 'B/vsx/vsx', 'name': 'AAVSO VSX'},
47
+ 'apass': {'vizier': 'II/336/apass9', 'name': 'APASS DR9'},
48
+ 'sdss': {
49
+ 'vizier': 'V/147/sdss12',
50
+ 'name': 'SDSS DR12',
51
+ 'extra': ['_RAJ2000', '_DEJ2000'],
52
+ },
53
+ 'atlas': {
54
+ 'vizier': 'J/ApJ/867/105/refcat2',
55
+ 'name': 'ATLAS-REFCAT2',
56
+ 'extra': [
57
+ '_RAJ2000',
58
+ '_DEJ2000',
59
+ 'e_Gmag',
60
+ 'e_gmag',
61
+ 'e_rmag',
62
+ 'e_imag',
63
+ 'e_zmag',
64
+ 'e_Jmag',
65
+ 'e_Kmag',
66
+ ],
67
+ },
68
+ }
69
+
70
+
71
+ def get_cat_vizier(
72
+ ra0, dec0, sr0, catalog='ps1', limit=-1, filters={}, extra=[], get_distance=False, verbose=False
73
+ ):
74
+ """Download any catalogue from Vizier.
75
+
76
+ The catalogue may be anything recognizable by Vizier. For some most popular ones, we have additional support - we try to augment them with photometric measurements not originally present there, based on some analytical magnitude conversion formulae. These catalogues are:
77
+
78
+ - ps1 - Pan-STARRS DR1. We augment it with Johnson-Cousins B, V, R and I magnitudes
79
+ - gaiadr2 - Gaia DR2. We augment it with Johnson-Cousins B, V, R and I magnitudes, as well as Pan-STARRS and SDSS ones
80
+ - gaiaedr3 - Gaia eDR3
81
+ - gaiadr3syn - Gaia DR3 synthetic photometry based on XP spectra
82
+ - skymapper - SkyMapper DR1.1
83
+ - vsx - AAVSO Variable Stars Index
84
+ - apass - AAVSO APASS DR9
85
+ - sdss - SDSS DR12
86
+ - atlas - ATLAS-RefCat2, compilative all-sky reference catalogue with uniform zero-points in Pan-STARRS-like bands. We augment it with Johnson-Cousins B, V, R and I magnitudes the same way as Pan-STARRS.
87
+ - usnob1 - USNO-B1
88
+ - gsc - Guide Star Catalogue 2.2
89
+
90
+ :param ra0: Right Ascension of the field center, degrees
91
+ :param dec0: Declination of the field center, degrees
92
+ :param sr0: Field radius, degrees
93
+ :param catalog: Any Vizier catalogue identifier, or a catalogue short name (see above)
94
+ :param limit: Limit for the number of returned rows, optional
95
+ :param filters: Dictionary with column filters to be applied on Vizier side. Dictionary key is the column name, value - filter expression as documented at https://vizier.u-strasbg.fr/vizier/vizHelp/cst.htx
96
+ :param extra: List of extra column names to return in addition to default ones.
97
+ :param get_distance: If set, the distance from the field center will be returned in `_r` column.
98
+ :param verbose: Whether to show verbose messages during the run of the function or not. May be either boolean, or a `print`-like function.
99
+ :returns: astropy.table.Table with catalogue as returned by Vizier, with some additional columns added for supported catalogues.
100
+ """
101
+
102
+ # Simple Wrapper around print for logging in verbose mode only
103
+ log = (
104
+ (verbose if callable(verbose) else print)
105
+ if verbose
106
+ else lambda *args, **kwargs: None
107
+ )
108
+
109
+ # TODO: add positional errors
110
+
111
+ if catalog in catalogs:
112
+ # For some catalogs we may have some additional information
113
+ vizier_id = catalogs.get(catalog).get('vizier')
114
+ name = catalogs.get(catalog).get('name')
115
+
116
+ columns = (
117
+ ['*', 'RAJ2000', 'DEJ2000', 'e_RAJ2000', 'e_DEJ2000']
118
+ + extra
119
+ + catalogs.get(catalog).get('extra', [])
120
+ )
121
+ else:
122
+ vizier_id = catalog
123
+ name = catalog
124
+ columns = ['*', 'RAJ2000', 'DEJ2000', 'e_RAJ2000', 'e_DEJ2000'] + extra
125
+
126
+ log('Requesting from VizieR:', vizier_id, 'columns:', columns)
127
+ log('Center: %.3f %.3f' % (ra0, dec0), 'radius: %.3f' % sr0)
128
+ log('Filters:', filters)
129
+
130
+ vizier = Vizier(row_limit=limit, columns=columns, column_filters=filters)
131
+ cats = vizier.query_region(
132
+ SkyCoord(ra0, dec0, unit='deg'), radius=sr0 * u.deg, catalog=vizier_id
133
+ )
134
+
135
+ if not cats or not len(cats) == 1:
136
+ cats = vizier.query_region(
137
+ SkyCoord(ra0, dec0, unit='deg'),
138
+ radius=sr0 * u.deg,
139
+ catalog=vizier_id,
140
+ cache=False,
141
+ )
142
+
143
+ if not cats or not len(cats) == 1:
144
+ log('Error requesting catalogue', catalog)
145
+ return None
146
+
147
+ cat = cats[0]
148
+ cat.meta['vizier_id'] = vizier_id
149
+ cat.meta['name'] = name
150
+
151
+ log('Got', len(cat), 'entries with', len(cat.colnames), 'columns')
152
+
153
+ # Fix _RAJ2000/_DEJ2000
154
+ if (
155
+ '_RAJ2000' in cat.keys()
156
+ and '_DEJ2000' in cat.keys()
157
+ and not 'RAJ2000' in cat.keys()
158
+ ):
159
+ cat.rename_columns(['_RAJ2000', '_DEJ2000'], ['RAJ2000', 'DEJ2000'])
160
+
161
+ if get_distance and 'RAJ2000' in cat.colnames and 'DEJ2000' in cat.colnames:
162
+ log("Augmenting the catalogue with distances from field center")
163
+ cat['_r'] = astrometry.spherical_distance(ra0, dec0, cat['RAJ2000'], cat['DEJ2000'])
164
+
165
+ # Augment catalogue with additional bandpasses
166
+
167
+ if catalog == 'ps1' or catalog == 'atlas':
168
+ # Alternative PS1 transfromation from https://arxiv.org/pdf/1706.06147.pdf, Stetson, seems better with Landolt than official one
169
+ # cat['B'] = cat['gmag'] + 0.199 + 0.540*(cat['gmag'] - cat['rmag']) + 0.016*(cat['gmag'] - cat['rmag'])**2
170
+ # cat['V'] = cat['gmag'] - 0.020 - 0.498*(cat['gmag'] - cat['rmag']) - 0.008*(cat['gmag'] - cat['rmag'])**2
171
+ # cat['R'] = cat['rmag'] - 0.163 - 0.086*(cat['gmag'] - cat['rmag']) - 0.061*(cat['gmag'] - cat['rmag'])**2
172
+ # cat['I'] = cat['imag'] - 0.387 - 0.123*(cat['gmag'] - cat['rmag']) - 0.034*(cat['gmag'] - cat['rmag'])**2
173
+
174
+ log("Augmenting the catalogue with Johnson-Cousins photometry")
175
+
176
+ # My own fit on Landolt+Stetson standards from https://arxiv.org/pdf/2205.06186.pdf
177
+ pB1, pB2 = (
178
+ [
179
+ 0.10339527794499666,
180
+ -0.492149523946056,
181
+ 1.2093816061394638,
182
+ 0.061925048331498395,
183
+ ],
184
+ [
185
+ -0.2571974580267897,
186
+ 0.9211495207523038,
187
+ -0.8243222108864755,
188
+ 0.0619250483314976,
189
+ ],
190
+ )
191
+ pV1, pV2 = (
192
+ [
193
+ -0.011452922062676726,
194
+ -9.949308251868327e-05,
195
+ -0.4650511584366353,
196
+ -0.007076854914511554,
197
+ ],
198
+ [
199
+ 0.012749150754020416,
200
+ 0.057554580469724864,
201
+ -0.09019328095355343,
202
+ -0.007076854914511329,
203
+ ],
204
+ )
205
+ pR1, pR2 = (
206
+ [
207
+ 0.004905242602502597,
208
+ -0.046545625824660514,
209
+ 0.07830702317352654,
210
+ -0.08438139204305026,
211
+ ],
212
+ [
213
+ -0.07782426914647306,
214
+ 0.14090289318728444,
215
+ -0.3634922073369279,
216
+ -0.08438139204305031,
217
+ ],
218
+ )
219
+ pI1, pI2 = (
220
+ [
221
+ -0.02274814414922734,
222
+ 0.048462952908062046,
223
+ -0.046965058282604985,
224
+ -0.19478935830847588,
225
+ ],
226
+ [
227
+ 0.025124060889537177,
228
+ -0.048672562735374666,
229
+ -1.199591061144479,
230
+ -0.1947893583084762,
231
+ ],
232
+ )
233
+
234
+ cat['Bmag'] = (
235
+ cat['gmag']
236
+ + np.polyval(pB1, cat['gmag'] - cat['rmag'])
237
+ + np.polyval(pB2, cat['rmag'] - cat['imag'])
238
+ )
239
+ cat['Vmag'] = (
240
+ cat['gmag']
241
+ + np.polyval(pV1, cat['gmag'] - cat['rmag'])
242
+ + np.polyval(pV2, cat['rmag'] - cat['imag'])
243
+ )
244
+ cat['Rmag'] = (
245
+ cat['rmag']
246
+ + np.polyval(pR1, cat['gmag'] - cat['rmag'])
247
+ + np.polyval(pR2, cat['rmag'] - cat['imag'])
248
+ )
249
+ cat['Imag'] = (
250
+ cat['imag']
251
+ + np.polyval(pI1, cat['gmag'] - cat['rmag'])
252
+ + np.polyval(pI2, cat['imag'] - cat['zmag'])
253
+ )
254
+
255
+ cat['e_Bmag'] = cat['e_gmag']
256
+ cat['e_Vmag'] = cat['e_gmag']
257
+ cat['e_Rmag'] = cat['e_rmag']
258
+ cat['e_Imag'] = cat['e_imag']
259
+
260
+ # Copies of columns for convenience
261
+ for _ in ['B', 'V', 'R', 'I']:
262
+ cat[_] = cat[_ + 'mag']
263
+
264
+ cat['good'] = (cat['gmag'] - cat['rmag'] > -0.5) & (
265
+ cat['gmag'] - cat['rmag'] < 2.5
266
+ )
267
+ cat['good'] &= (cat['rmag'] - cat['imag'] > -0.5) & (
268
+ cat['rmag'] - cat['imag'] < 2.0
269
+ )
270
+ cat['good'] &= (cat['imag'] - cat['zmag'] > -0.5) & (
271
+ cat['imag'] - cat['zmag'] < 1.0
272
+ )
273
+
274
+ # to SDSS, zero points and color terms from https://arxiv.org/pdf/1203.0297.pdf
275
+ cat['g_SDSS'] = (
276
+ cat['gmag']
277
+ + 0.013
278
+ + 0.145 * (cat['gmag'] - cat['rmag'])
279
+ + 0.019 * (cat['gmag'] - cat['rmag']) ** 2
280
+ )
281
+ cat['r_SDSS'] = (
282
+ cat['rmag']
283
+ - 0.001
284
+ + 0.004 * (cat['gmag'] - cat['rmag'])
285
+ + 0.007 * (cat['gmag'] - cat['rmag']) ** 2
286
+ )
287
+ cat['i_SDSS'] = (
288
+ cat['imag']
289
+ - 0.005
290
+ + 0.011 * (cat['gmag'] - cat['rmag'])
291
+ + 0.010 * (cat['gmag'] - cat['rmag']) ** 2
292
+ )
293
+ cat['z_SDSS'] = cat['zmag']
294
+
295
+ elif catalog == 'gaiadr2':
296
+ log("Augmenting the catalogue with Johnson-Cousins photometry")
297
+
298
+ # My simple Gaia DR2 to Johnson conversion based on Stetson standards
299
+ pB = [
300
+ -0.05927724559795761,
301
+ 0.4224326324292696,
302
+ 0.626219707920836,
303
+ -0.011211539139725953,
304
+ ]
305
+ pV = [
306
+ 0.0017624722901609662,
307
+ 0.15671377090187089,
308
+ 0.03123927839356175,
309
+ 0.041448557506784556,
310
+ ]
311
+ pR = [
312
+ 0.02045449129406191,
313
+ 0.054005149296716175,
314
+ -0.3135475489352255,
315
+ 0.020545083667168156,
316
+ ]
317
+ pI = [
318
+ 0.005092289380850884,
319
+ 0.07027022935721515,
320
+ -0.7025553064161775,
321
+ -0.02747532184796779,
322
+ ]
323
+
324
+ pCB = [876.4047401692277, 5.114021693079334, -2.7332873314449326, 0]
325
+ pCV = [98.03049528983964, 20.582521666713028, 0.8690079603974803, 0]
326
+ pCR = [347.42190542330945, 39.42482430363565, 0.8626828845232541, 0]
327
+ pCI = [79.4028706486939, 9.176899238787003, -0.7826315256072135, 0]
328
+
329
+ g = cat['Gmag']
330
+ bp_rp = cat['BPmag'] - cat['RPmag']
331
+
332
+ # phot_bp_rp_excess_factor == E(BR/RP) == E_BR_RP_
333
+ Cstar = cat['E_BR_RP_'] - np.polyval(
334
+ [-0.00445024, 0.0570293, -0.02810592, 1.20477819], bp_rp
335
+ )
336
+
337
+ # https://www.cosmos.esa.int/web/gaia/dr2-known-issues#PhotometrySystematicEffectsAndResponseCurves
338
+ gcorr = g.copy()
339
+ gcorr[(g > 2) & (g < 6)] = (
340
+ -0.047344
341
+ + 1.16405 * g[(g > 2) & (g < 6)]
342
+ - 0.046799 * g[(g > 2) & (g < 6)] ** 2
343
+ + 0.0035015 * g[(g > 2) & (g < 6)] ** 3
344
+ )
345
+ gcorr[(g > 6) & (g < 16)] = g[(g > 6) & (g < 16)] - 0.0032 * (
346
+ g[(g > 6) & (g < 16)] - 6
347
+ )
348
+ gcorr[g > 16] = g[g > 16] - 0.032
349
+ g = gcorr
350
+
351
+ cat['Bmag'] = g + np.polyval(pB, bp_rp) + np.polyval(pCB, Cstar)
352
+ cat['Vmag'] = g + np.polyval(pV, bp_rp) + np.polyval(pCV, Cstar)
353
+ cat['Rmag'] = g + np.polyval(pR, bp_rp) + np.polyval(pCR, Cstar)
354
+ cat['Imag'] = g + np.polyval(pI, bp_rp) + np.polyval(pCI, Cstar)
355
+
356
+ # Rough estimation of magnitude error, just from G band
357
+ for _ in ['B', 'V', 'R', 'I', 'g', 'r']:
358
+ cat['e_' + _ + 'mag'] = cat['e_Gmag']
359
+
360
+ # Copies of columns for convenience
361
+ for _ in ['B', 'V', 'R', 'I']:
362
+ cat[_] = cat[_ + 'mag']
363
+
364
+ # to PS1 - FIXME: there are some uncorrected color and magnitude trends!
365
+ cat['gmag'] = (
366
+ cat['Bmag']
367
+ - 0.108
368
+ - 0.485 * (cat['Bmag'] - cat['Vmag'])
369
+ - 0.032 * (cat['Bmag'] - cat['Vmag']) ** 2
370
+ )
371
+ cat['rmag'] = (
372
+ cat['Vmag']
373
+ + 0.082
374
+ - 0.462 * (cat['Bmag'] - cat['Vmag'])
375
+ + 0.041 * (cat['Bmag'] - cat['Vmag']) ** 2
376
+ )
377
+
378
+ # to SDSS, from https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/chap_cu5pho/sec_cu5pho_calibr/ssec_cu5pho_PhotTransf.html
379
+ cat['g_SDSS'] = g - (
380
+ 0.13518 - 0.46245 * bp_rp - 0.25171 * bp_rp ** 2 + 0.021349 * bp_rp ** 3
381
+ )
382
+ cat['r_SDSS'] = g - (
383
+ -0.12879 + 0.24662 * bp_rp - 0.027464 * bp_rp ** 2 - 0.049465 * bp_rp ** 3
384
+ )
385
+ cat['i_SDSS'] = g - (-0.29676 + 0.64728 * bp_rp - 0.10141 * bp_rp ** 2)
386
+
387
+ elif catalog == 'skymapper':
388
+ # to PS1
389
+ for _ in ['u', 'g', 'r', 'i', 'z']:
390
+ cat[_ + 'mag'] = cat[_ + 'PSF']
391
+ cat['e_' + _ + 'mag'] = cat['e_' + _ + 'PSF']
392
+
393
+ log("Augmenting the catalogue with Johnson-Cousins photometry")
394
+
395
+ # Johnson-Cousins, copy from PS1 above
396
+ pB1, pB2 = (
397
+ [
398
+ 0.10339527794499666,
399
+ -0.492149523946056,
400
+ 1.2093816061394638,
401
+ 0.061925048331498395,
402
+ ],
403
+ [
404
+ -0.2571974580267897,
405
+ 0.9211495207523038,
406
+ -0.8243222108864755,
407
+ 0.0619250483314976,
408
+ ],
409
+ )
410
+ pV1, pV2 = (
411
+ [
412
+ -0.011452922062676726,
413
+ -9.949308251868327e-05,
414
+ -0.4650511584366353,
415
+ -0.007076854914511554,
416
+ ],
417
+ [
418
+ 0.012749150754020416,
419
+ 0.057554580469724864,
420
+ -0.09019328095355343,
421
+ -0.007076854914511329,
422
+ ],
423
+ )
424
+ pR1, pR2 = (
425
+ [
426
+ 0.004905242602502597,
427
+ -0.046545625824660514,
428
+ 0.07830702317352654,
429
+ -0.08438139204305026,
430
+ ],
431
+ [
432
+ -0.07782426914647306,
433
+ 0.14090289318728444,
434
+ -0.3634922073369279,
435
+ -0.08438139204305031,
436
+ ],
437
+ )
438
+ pI1, pI2 = (
439
+ [
440
+ -0.02274814414922734,
441
+ 0.048462952908062046,
442
+ -0.046965058282604985,
443
+ -0.19478935830847588,
444
+ ],
445
+ [
446
+ 0.025124060889537177,
447
+ -0.048672562735374666,
448
+ -1.199591061144479,
449
+ -0.1947893583084762,
450
+ ],
451
+ )
452
+
453
+ cat['Bmag'] = (
454
+ cat['gmag']
455
+ + np.polyval(pB1, cat['gmag'] - cat['rmag'])
456
+ + np.polyval(pB2, cat['rmag'] - cat['imag'])
457
+ )
458
+ cat['Vmag'] = (
459
+ cat['gmag']
460
+ + np.polyval(pV1, cat['gmag'] - cat['rmag'])
461
+ + np.polyval(pV2, cat['rmag'] - cat['imag'])
462
+ )
463
+ cat['Rmag'] = (
464
+ cat['rmag']
465
+ + np.polyval(pR1, cat['gmag'] - cat['rmag'])
466
+ + np.polyval(pR2, cat['rmag'] - cat['imag'])
467
+ )
468
+ cat['Imag'] = (
469
+ cat['imag']
470
+ + np.polyval(pI1, cat['gmag'] - cat['rmag'])
471
+ + np.polyval(pI2, cat['imag'] - cat['zmag'])
472
+ )
473
+
474
+ cat['e_Bmag'] = cat['e_gmag']
475
+ cat['e_Vmag'] = cat['e_gmag']
476
+ cat['e_Rmag'] = cat['e_rmag']
477
+ cat['e_Imag'] = cat['e_imag']
478
+
479
+ # Copies of columns for convenience
480
+ for _ in ['B', 'V', 'R', 'I']:
481
+ cat[_] = cat[_ + 'mag']
482
+
483
+ elif catalog == 'apass':
484
+ log("Augmenting the catalogue with Cousins R and I photometry")
485
+
486
+ # My own fit based on Landolt standards
487
+ cat['Rmag'] = (
488
+ cat['r_mag']
489
+ - 0.157
490
+ - 0.087 * (cat['g_mag'] - cat['r_mag'])
491
+ - 0.014 * (cat['g_mag'] - cat['r_mag']) ** 2
492
+ )
493
+ cat['e_Rmag'] = cat['e_r_mag']
494
+
495
+ cat['Imag'] = (
496
+ cat['i_mag']
497
+ - 0.354
498
+ - 0.118 * (cat['g_mag'] - cat['r_mag'])
499
+ - 0.004 * (cat['g_mag'] - cat['r_mag']) ** 2
500
+ )
501
+ cat['e_Imag'] = cat['e_i_mag']
502
+
503
+ # Copies of columns for convenience
504
+ for _ in ['B', 'V', 'R', 'I']:
505
+ cat[_] = cat[_ + 'mag']
506
+
507
+ elif catalog == 'gaiadr3syn':
508
+ # Compute magnitude errors from flux errors
509
+ for name in ['U', 'B', 'V', 'R', 'I', 'u', 'g', 'r', 'i', 'z', 'y']:
510
+ cat['e_' + name + 'mag'] = (
511
+ 2.5 / np.log(10) * cat['e_F' + name] / cat['F' + name]
512
+ )
513
+
514
+ log("Converting the catalogue Sloan magnitudes to Pan-STARRS ones")
515
+
516
+ # umag, gmag, rmag, imag and zmag are Sloan ugriz magnitudes! Let's get PS1 ones instead
517
+ # Fits are based on clean Landolt sample from https://arxiv.org/pdf/1203.0297.pdf
518
+ pg = [-0.030414391501015867, -0.09960002492299584, -0.002910024005294562]
519
+ pr = [-0.009566553708653305, 0.014924591443344211, -0.003928147919030857]
520
+ pi = [-0.010802807724098494, 0.01124900218746879, 0.01274293783734852]
521
+ pz = [-0.0031896767661109523, 0.06537983414287968, 0.007695587806229381]
522
+
523
+ for _ in ['u', 'g', 'r', 'i', 'z']:
524
+ cat[_ + '_SDSS'] = cat[_ + 'mag']
525
+
526
+ cat['gmag'] = cat['g_SDSS'] + np.polyval(pg, cat['g_SDSS'] - cat['r_SDSS'])
527
+ cat['rmag'] = cat['r_SDSS'] + np.polyval(pr, cat['g_SDSS'] - cat['r_SDSS'])
528
+ cat['imag'] = cat['i_SDSS'] + np.polyval(pi, cat['g_SDSS'] - cat['r_SDSS'])
529
+ cat['zmag'] = cat['z_SDSS'] + np.polyval(pz, cat['g_SDSS'] - cat['r_SDSS'])
530
+
531
+ return cat
532
+
533
+
534
+ def xmatch_objects(obj, catalog='ps1', sr=3 / 3600, col_ra='ra', col_dec='dec'):
535
+ """Cross-match object list with Vizier catalogue using CDS XMatch service.
536
+
537
+ Any Vizier catalogue may be used for cross-matching.
538
+
539
+ :param obj: astropy.table.Table with objects
540
+ :param catalog: Any Vizier catalogue identifier, or a catalogue short name
541
+ :param sr: Cross-matching radius in degrees
542
+ :param col_ra: Column name in `obj` table containing Right Ascension values
543
+ :param col_dec: Column name in `obj` table containing Declination values
544
+ :returns: The table of matched objects augmented with some fields from the Vizier catalogue.
545
+ """
546
+
547
+ if catalog in catalogs:
548
+ vizier_id = catalogs.get(catalog)['vizier']
549
+ else:
550
+ vizier_id = catalog
551
+
552
+ xcat = XMatch().query(
553
+ cat1=obj,
554
+ cat2='vizier:' + vizier_id,
555
+ max_distance=sr * u.deg,
556
+ colRA1=col_ra,
557
+ colDec1=col_dec,
558
+ )
559
+
560
+ return xcat
561
+
562
+
563
+ def xmatch_skybot(
564
+ obj, sr=10 / 3600, time=None, col_ra='ra', col_dec='dec', col_id='id'
565
+ ):
566
+ """Cross-match object list with positions of Solar System objects using SkyBoT service
567
+
568
+ The routine works by requesting the list of all solar system objects in a cone containing all
569
+ input objects, and then cross-matching them using the radius defined by `sr` parameter. Then it
570
+ returns the table of solar system objects plus a column of unique identifiers corresponding
571
+ to user objects.
572
+
573
+ :param obj: astropy.table.Table with objects
574
+ :param sr: Cross-matching radius in degrees
575
+ :param time: Time of the observation corresponding to the objects
576
+ :param col_ra: Column name in `obj` table containing Right Ascension values
577
+ :param col_dec: Column name in `obj` table containing Declination values
578
+ :param col_id: Column name in `obj` table containing some unique object identifier
579
+ :returns: The table of solar system objects augmented with `col_id` column of matched objects.
580
+ """
581
+
582
+ ra0, dec0, sr0 = astrometry.get_objects_center(obj)
583
+
584
+ try:
585
+ # Query SkyBot for (a bit larger than) our FOV at our time
586
+ xcat = Skybot.cone_search(
587
+ SkyCoord(ra0, dec0, unit='deg'), (sr0 + 2.0 * sr) * u.deg, Time(time)
588
+ )
589
+ except (RuntimeError, KeyError, ConnectionError, OSError):
590
+ # Nothing found in SkyBot
591
+ return None
592
+
593
+ # Cross-match objects
594
+ oidx, cidx, dist = astrometry.spherical_match(
595
+ obj[col_ra], obj[col_dec], xcat['RA'], xcat['DEC'], 10 / 3600
596
+ )
597
+
598
+ # Annotate the table with id from objects so that it is possible to identify the matches
599
+ xcat[col_id] = MaskedColumn(len(xcat), dtype=np.dtype(obj[col_id][0]))
600
+ xcat[col_id].mask = True
601
+ xcat[col_id][cidx] = obj[col_id][oidx]
602
+ xcat[col_id][cidx].mask = False
603
+
604
+ return xcat
605
+
606
+
607
+ def xmatch_ned(obj, sr=3 / 3600, col_ra='ra', col_dec='dec', col_id='id'):
608
+ """Cross-match object list with NED database entries
609
+
610
+ The routine is extremely inefficient as it has to query the objects one by one!
611
+
612
+ :param obj: astropy.table.Table with objects
613
+ :param sr: Cross-matching radius in degrees
614
+ :param col_ra: Column name in `obj` table containing Right Ascension values
615
+ :param col_dec: Column name in `obj` table containing Declination values
616
+ :param col_id: Column name in `obj` table containing some unique object identifier
617
+ :returns: The table of NED objects augmented with `id` column containing the identifiers from `col_id` columns of matched objects.
618
+
619
+ """
620
+
621
+ xcat = []
622
+
623
+ # FIXME: is there more optimal way to query NED for multiple sky positions?..
624
+ for row in obj:
625
+ res = Ned().query_region(
626
+ SkyCoord(row[col_ra], row[col_dec], unit='deg'), sr * u.deg
627
+ )
628
+
629
+ if res:
630
+ res['id'] = row[col_id]
631
+
632
+ xcat.append(res)
633
+
634
+ if xcat:
635
+ xcat = vstack(xcat, join_type='exact', metadata_conflicts='silent')
636
+
637
+ return xcat
@@ -76,7 +76,7 @@ def get_objects_sep(
76
76
  verbose=True,
77
77
  **kwargs
78
78
  ):
79
- """Opject detection and simple aperture photometry using `SEP <https://github.com/kbarbary/sep>`_ routines, with the signature as similar as possible to :func:`~stdpipe.photometry.get_objects_sextractor` function.
79
+ """Object detection and simple aperture photometry using `SEP <https://github.com/kbarbary/sep>`_ routines, with the signature as similar as possible to :func:`~stdpipe.photometry.get_objects_sextractor` function.
80
80
 
81
81
  Detection flags are documented at https://sep.readthedocs.io/en/v1.1.x/reference.html - they are different from SExtractor ones!
82
82
 
@@ -953,8 +953,10 @@ def match(
953
953
  if get_err:
954
954
  # It follows the implementation from https://github.com/statsmodels/statsmodels/blob/081fc6e85868308aa7489ae1b23f6e72f5662799/statsmodels/base/model.py#L1383
955
955
  # FIXME: crashes on large numbers of stars?..
956
- # err = np.sqrt(np.dot(X, np.dot(C.cov_params()[0:X.shape[1], 0:X.shape[1]], np.transpose(X))).diagonal())
957
- err = np.zeros_like(x)
956
+ if len(x) < 5000:
957
+ err = np.sqrt(np.dot(X, np.dot(C.cov_params()[0:X.shape[1], 0:X.shape[1]], np.transpose(X))).diagonal())
958
+ else:
959
+ err = np.zeros_like(x)
958
960
  if add_intrinsic_rms:
959
961
  err = np.hypot(err, intrinsic_rms)
960
962
  return err
@@ -1127,7 +1129,8 @@ def measure_objects(
1127
1129
 
1128
1130
  log('Using aperture radius %.1f pixels' % aper)
1129
1131
 
1130
- positions = [(_['x'], _['y']) for _ in obj]
1132
+ # FIXME: is there any better way to exclude some positions from photometry?..
1133
+ positions = [(_['x'], _['y']) if np.isfinite(_['x']) and np.isfinite(_['y']) else (-1000, -1000) for _ in obj]
1131
1134
  apertures = photutils.CircularAperture(positions, r=aper)
1132
1135
  # Use just a minimal mask here so that the flux from 'soft-masked' (e.g. saturated) pixels is still counted
1133
1136
  res = photutils.aperture_photometry(image1, apertures, error=err, mask=mask0)
@@ -1172,11 +1175,8 @@ def measure_objects(
1172
1175
  mask_overlap = bg_mask.multiply(mask | mask0)
1173
1176
 
1174
1177
  if bg_overlap is None or mask_overlap is None:
1175
- row[
1176
- 'flags'
1177
- ] |= (
1178
- 0x400
1179
- ) # Flag the values where the annulus is completely outside the image
1178
+ # Flag the values where the annulus is completely outside the image
1179
+ row['flags'] |= 0x400
1180
1180
  continue
1181
1181
 
1182
1182
  bg_vals = bg_overlap[bg_mask.data > 0]
@@ -1199,9 +1199,8 @@ def measure_objects(
1199
1199
  row['bg_local'] = local_bg_est
1200
1200
  row['bg_fluxerr'] = bg_stats[2] * np.sqrt(area['aperture_sum'])
1201
1201
  else:
1202
- row[
1203
- 'flags'
1204
- ] |= 0x400 # Flag the values where local bg estimation failed
1202
+ # Flag the values where local bg estimation failed
1203
+ row['flags'] |= 0x400
1205
1204
 
1206
1205
  idx = obj['flux'] > 0
1207
1206
  for _ in ['mag', 'magerr']:
@@ -1028,7 +1028,7 @@ def get_detection_limit(obj, sn=5, method='sn', verbose=True):
1028
1028
  if method == 'sn':
1029
1029
  log('Estimating detection limit using S/N vs magnitude method')
1030
1030
  mag0 = photometry.get_detection_limit_sn(
1031
- obj['mag_calib'], 1 / obj['mag_calib_err'], sn=sn, verbose=verbose
1031
+ obj['mag_calib'], 1 / obj['magerr'], sn=sn, verbose=verbose
1032
1032
  )
1033
1033
  elif method == 'bg':
1034
1034
  log('Estimating detection limit using background noise method')
@@ -5,7 +5,8 @@ import matplotlib.pyplot as plt
5
5
  from matplotlib.patches import Circle
6
6
 
7
7
  from astropy.stats import mad_std
8
- from astropy.visualization import simple_norm
8
+ from astropy.visualization import simple_norm, ImageNormalize
9
+ from astropy.visualization.stretch import HistEqStretch
9
10
 
10
11
  from mpl_toolkits.axes_grid1 import make_axes_locatable
11
12
  from scipy.stats import binned_statistic_2d
@@ -76,12 +77,26 @@ def imshow(
76
77
  kwargs['interpolation'] = 'bicubic'
77
78
 
78
79
  if stretch and stretch != 'linear':
79
- kwargs['norm'] = simple_norm(
80
- image,
81
- stretch,
82
- min_cut=kwargs.pop('vmin', None),
83
- max_cut=kwargs.pop('vmax', None),
84
- )
80
+ if stretch == 'histeq':
81
+ data = image
82
+ if 'vmin' in kwargs:
83
+ data = data[data >= kwargs['vmin']]
84
+ if 'vmax' in kwargs:
85
+ data = data[data <= kwargs['vmax']]
86
+
87
+ kwargs['norm'] = ImageNormalize(
88
+ stretch=HistEqStretch(data),
89
+ vmin=kwargs.pop('vmin', None),
90
+ vmax=kwargs.pop('vmax', None),
91
+ )
92
+ else:
93
+ kwargs['norm'] = simple_norm(
94
+ image,
95
+ stretch,
96
+ min_cut=kwargs.pop('vmin', None),
97
+ max_cut=kwargs.pop('vmax', None),
98
+ power=2,
99
+ )
85
100
 
86
101
  img = ax.imshow(image, **kwargs)
87
102
  if not show_axis:
@@ -531,7 +546,9 @@ def plot_photometric_match(
531
546
  return ax
532
547
 
533
548
 
534
- def plot_detection_limit(obj, sn=5, mag_name=None, ax=None):
549
+ def plot_detection_limit(
550
+ obj, sn=5, mag_name=None, obj_col_mag='mag_calib', obj_col_mag_err='magerr', ax=None
551
+ ):
535
552
  """
536
553
  Plot the details of detection limit estimation
537
554
 
@@ -544,8 +561,8 @@ def plot_detection_limit(obj, sn=5, mag_name=None, ax=None):
544
561
  if ax is None:
545
562
  ax = plt.gca()
546
563
 
547
- mag = obj['mag_calib']
548
- mag_sn = 1 / obj['mag_calib_err']
564
+ mag = obj[obj_col_mag]
565
+ mag_sn = 1 / obj[obj_col_mag_err]
549
566
 
550
567
  ax.plot(
551
568
  mag, mag_sn, '.', alpha=(0.2 if len(mag_sn) > 1000 else 0.4), label='Objects'
@@ -588,7 +605,9 @@ def plot_detection_limit(obj, sn=5, mag_name=None, ax=None):
588
605
  ax.set_ylabel('Signal / Noise')
589
606
 
590
607
 
591
- def plot_mag_histogram(obj, cat=None, cat_col_mag=None, sn=None, ax=None):
608
+ def plot_mag_histogram(
609
+ obj, cat=None, cat_col_mag=None, sn=None, obj_col_mag='mag_calib', obj_col_mag_err='magerr', ax=None
610
+ ):
592
611
  """
593
612
  Plot the histogram of calibrated magnitudes for detected objects,
594
613
  and optionally the catalogue.
@@ -603,8 +622,9 @@ def plot_mag_histogram(obj, cat=None, cat_col_mag=None, sn=None, ax=None):
603
622
  if ax is None:
604
623
  ax = plt.gca()
605
624
 
606
- mag = obj['mag_calib']
607
- magerr = obj['mag_calib_err']
625
+ mag = obj[obj_col_mag]
626
+ mag_sn = 1 / obj[obj_col_mag_err]
627
+
608
628
  idx = obj['flags'] == 0
609
629
 
610
630
  vmin = np.nanmin(mag)
@@ -663,9 +683,6 @@ def plot_mag_histogram(obj, cat=None, cat_col_mag=None, sn=None, ax=None):
663
683
  ax.set_xlabel('Magnitude')
664
684
 
665
685
  if sn:
666
- mag = obj['mag_calib']
667
- mag_sn = 1 / obj['mag_calib_err']
668
-
669
686
  mag0 = photometry.get_detection_limit_sn(mag, mag_sn, sn=sn)
670
687
  if mag0 is not None:
671
688
  ax.axvline(mag0, ls=':', color='red', alpha=0.3, label=f"S/N={sn}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stdpipe
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Simple Transient Detection Pipeline
5
5
  Home-page: https://github.com/karpov-sv/stdpipe
6
6
  Author: Sergey Karpov
@@ -8,6 +8,7 @@ stdpipe/astrometry.py
8
8
  stdpipe/catalogs.py
9
9
  stdpipe/cutouts.py
10
10
  stdpipe/db.py
11
+ stdpipe/flycheck_catalogs.py
11
12
  stdpipe/lcs.py
12
13
  stdpipe/photometry.py
13
14
  stdpipe/pipeline.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes