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/utils.py
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import requests
|
|
4
|
+
import dateutil
|
|
5
|
+
import shlex
|
|
6
|
+
|
|
7
|
+
from tqdm.auto import tqdm
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from astropy.io import fits
|
|
11
|
+
from astropy.coordinates import SkyCoord
|
|
12
|
+
from astropy import units as u
|
|
13
|
+
from astropy.time import Time
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def breakpoint():
|
|
17
|
+
try:
|
|
18
|
+
from IPython.core.debugger import Tracer
|
|
19
|
+
|
|
20
|
+
Tracer()()
|
|
21
|
+
except:
|
|
22
|
+
import pdb
|
|
23
|
+
|
|
24
|
+
pdb.set_trace()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def make_jname(ra, dec):
|
|
28
|
+
radec = SkyCoord(ra, dec, unit='deg')
|
|
29
|
+
return "J%s%s" % (
|
|
30
|
+
radec.ra.to_string(unit=u.hourangle, sep='', precision=2, pad=True),
|
|
31
|
+
radec.dec.to_string(sep='', precision=1, alwayssign=True, pad=True),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_data_path(dataname):
|
|
36
|
+
"""
|
|
37
|
+
Returns full path to the data file located in the module data/ folder
|
|
38
|
+
"""
|
|
39
|
+
return os.path.join(os.path.dirname(__file__), 'data', dataname)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def download(url, filename=None, overwrite=False, verbose=False):
|
|
43
|
+
# Simple wrapper around print for logging in verbose mode only
|
|
44
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
45
|
+
|
|
46
|
+
if not overwrite and filename is not None and os.path.exists(filename):
|
|
47
|
+
log(filename, 'already downloaded')
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
response = requests.get(url, stream=True, allow_redirects=True)
|
|
51
|
+
if response.status_code != 200:
|
|
52
|
+
log('Error %s downloading from %s' % (response.status_code, url))
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
# FIXME: if server is compressing the data, Content-Length here will be wrong?..
|
|
56
|
+
size = int(response.headers.get('Content-Length', 0))
|
|
57
|
+
|
|
58
|
+
if filename is None:
|
|
59
|
+
# Some logic to guess filename from headers
|
|
60
|
+
tmp = re.findall("filename=(.+)", response.headers.get('Content-Disposition', ''))
|
|
61
|
+
if len(tmp):
|
|
62
|
+
filename = tmp[1]
|
|
63
|
+
else:
|
|
64
|
+
filename = 'download'
|
|
65
|
+
|
|
66
|
+
# TODO: check file existence here again?..
|
|
67
|
+
|
|
68
|
+
desc = os.path.basename(filename)
|
|
69
|
+
|
|
70
|
+
log('Downloading %s from %s...' % (filename, url))
|
|
71
|
+
|
|
72
|
+
length = 0
|
|
73
|
+
|
|
74
|
+
if verbose:
|
|
75
|
+
progress = tqdm(desc=desc, total=size, unit='iB', unit_scale=True, unit_divisor=1024)
|
|
76
|
+
else:
|
|
77
|
+
progress = None
|
|
78
|
+
|
|
79
|
+
with open(filename, 'wb') as file:
|
|
80
|
+
for chunk in response.iter_content(chunk_size=1024):
|
|
81
|
+
chunksize = file.write(chunk)
|
|
82
|
+
if progress is not None:
|
|
83
|
+
progress.update(chunksize)
|
|
84
|
+
length += chunksize # len(chunk)
|
|
85
|
+
|
|
86
|
+
if progress is not None:
|
|
87
|
+
progress.close()
|
|
88
|
+
|
|
89
|
+
if size and length < size:
|
|
90
|
+
log('Downloaded %d bytes, was expecting %d' % (length, size))
|
|
91
|
+
return False
|
|
92
|
+
else:
|
|
93
|
+
log('Successfully downloaded %d bytes' % length)
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_obs_time(header=None, filename=None, string=None, get_datetime=False, verbose=False):
|
|
98
|
+
"""Extract date and time of observations from a FITS header or string.
|
|
99
|
+
|
|
100
|
+
Tries the following FITS keywords in order: ``DATE-OBS``, ``DATEOBS``,
|
|
101
|
+
``DATE``, ``TIME-OBS``, ``TIMEOBS``, ``UT``, ``MJD``, ``JD``.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
header : astropy.io.fits.Header, optional
|
|
106
|
+
FITS header containing observation time keywords.
|
|
107
|
+
filename : str, optional
|
|
108
|
+
Path to a FITS file; its header is loaded if ``header`` is not provided.
|
|
109
|
+
string : str, optional
|
|
110
|
+
Time string to parse directly instead of using a FITS header.
|
|
111
|
+
get_datetime : bool, optional
|
|
112
|
+
If True, return a :class:`datetime.datetime` instead of
|
|
113
|
+
:class:`astropy.time.Time`.
|
|
114
|
+
verbose : bool or callable, optional
|
|
115
|
+
Whether to show verbose messages. May be boolean or a ``print``-like callable.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
astropy.time.Time or datetime.datetime or None
|
|
120
|
+
Parsed observation time, or None if parsing fails.
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
# Simple wrapper around print for logging in verbose mode only
|
|
124
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
125
|
+
|
|
126
|
+
# Simple wrapper to display parsed value and convert it as necessary
|
|
127
|
+
def convert_time(time):
|
|
128
|
+
if isinstance(time, float):
|
|
129
|
+
# Try to parse floating-point value as MJD or JD, depending on the value
|
|
130
|
+
if time > 0 and time < 100000:
|
|
131
|
+
log('Assuming it is MJD')
|
|
132
|
+
time = Time(time, format='mjd')
|
|
133
|
+
elif time > 2400000 and time < 2500000:
|
|
134
|
+
log('Assuming it is JD')
|
|
135
|
+
time = Time(time, format='jd')
|
|
136
|
+
else:
|
|
137
|
+
# Then it is probably an Unix time?..
|
|
138
|
+
log('Assuming it is Unix time')
|
|
139
|
+
time = Time(time, format='unix')
|
|
140
|
+
|
|
141
|
+
else:
|
|
142
|
+
if isinstance(time, str):
|
|
143
|
+
# Special case where some telescope used '-' for time separation instead of ISO ':'
|
|
144
|
+
m = re.fullmatch(
|
|
145
|
+
r"(\d\d\d\d-\d\d-\d\dT\d\d)-(\d\d)-(\d\d(?:\.\d{1,6})?)", time.strip()
|
|
146
|
+
)
|
|
147
|
+
if m:
|
|
148
|
+
time = ":".join(m.groups())
|
|
149
|
+
time = Time(time)
|
|
150
|
+
|
|
151
|
+
log('Time parsed as:', time.iso)
|
|
152
|
+
if get_datetime:
|
|
153
|
+
return time.datetime
|
|
154
|
+
else:
|
|
155
|
+
return time
|
|
156
|
+
|
|
157
|
+
if string:
|
|
158
|
+
log('Parsing user-provided time string:', string)
|
|
159
|
+
try:
|
|
160
|
+
return convert_time(dateutil.parser.parse(string))
|
|
161
|
+
except dateutil.parser.ParserError as err:
|
|
162
|
+
log('Could not parse user-provided string:', err)
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
if header is None:
|
|
166
|
+
log('Loading FITS header from', filename)
|
|
167
|
+
header = fits.getheader(filename)
|
|
168
|
+
|
|
169
|
+
for dkey in ['DATE-OBS', 'DATEOBS', 'DATE', 'TIME-OBS', 'TIMEOBS', 'UT', 'MJD', 'JD']:
|
|
170
|
+
if dkey in header:
|
|
171
|
+
log('Found ' + dkey + ':', header[dkey])
|
|
172
|
+
# First try to parse standard ISO time
|
|
173
|
+
try:
|
|
174
|
+
return convert_time(header[dkey])
|
|
175
|
+
except:
|
|
176
|
+
log('Could not parse ' + dkey + ' using Astropy parser')
|
|
177
|
+
|
|
178
|
+
for tkey in ['TIME-OBS', 'TIMEOBS', 'UT']:
|
|
179
|
+
if tkey in header:
|
|
180
|
+
log('Found ' + tkey + ':', header[tkey])
|
|
181
|
+
try:
|
|
182
|
+
return convert_time(
|
|
183
|
+
dateutil.parser.parse(header[dkey] + ' ' + header[tkey])
|
|
184
|
+
)
|
|
185
|
+
except dateutil.parser.ParserError as err:
|
|
186
|
+
log('Could not parse ' + dkey + ' + ' + tkey + ':', err)
|
|
187
|
+
|
|
188
|
+
log('Unsupported FITS header time format')
|
|
189
|
+
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def table_get(table, colname, default=0):
|
|
194
|
+
"""
|
|
195
|
+
Simple wrapper to get table column, or default value if it is not present
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
if colname in table.colnames:
|
|
199
|
+
return table[colname]
|
|
200
|
+
elif default is None:
|
|
201
|
+
return None
|
|
202
|
+
elif hasattr(default, '__len__'):
|
|
203
|
+
# default value is array, return it
|
|
204
|
+
return default
|
|
205
|
+
else:
|
|
206
|
+
# Broadcast scalar to proper length
|
|
207
|
+
return default * np.ones(len(table), dtype=int)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def format_astromatic_opts(opts):
|
|
211
|
+
"""
|
|
212
|
+
Auxiliary function to format dictionary of options into Astromatic compatible command-line string.
|
|
213
|
+
Booleans are converted to Y/N, arrays to comma separated lists, strings are quoted when necessary
|
|
214
|
+
"""
|
|
215
|
+
result = []
|
|
216
|
+
|
|
217
|
+
for key in opts.keys():
|
|
218
|
+
if opts[key] is None:
|
|
219
|
+
pass
|
|
220
|
+
elif type(opts[key]) == bool:
|
|
221
|
+
result.append('-%s %s' % (key, 'Y' if opts[key] else 'N'))
|
|
222
|
+
else:
|
|
223
|
+
value = opts[key]
|
|
224
|
+
|
|
225
|
+
if type(value) == str:
|
|
226
|
+
value = shlex.quote(value)
|
|
227
|
+
elif hasattr(value, '__len__'):
|
|
228
|
+
value = ','.join([str(_) for _ in value])
|
|
229
|
+
|
|
230
|
+
result.append('-%s %s' % (key, value))
|
|
231
|
+
|
|
232
|
+
result = ' '.join(result)
|
|
233
|
+
|
|
234
|
+
return result
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def format_long_opts(opts):
|
|
238
|
+
"""
|
|
239
|
+
Auxiliary function to format dictionary of options into a command-line string.
|
|
240
|
+
Boolean options are added when True, strings are quoted when necessary
|
|
241
|
+
"""
|
|
242
|
+
result = []
|
|
243
|
+
|
|
244
|
+
for key in opts.keys():
|
|
245
|
+
if opts[key] is None:
|
|
246
|
+
pass
|
|
247
|
+
elif type(opts[key]) == bool:
|
|
248
|
+
if opts[key]:
|
|
249
|
+
result.append('--%s' % key)
|
|
250
|
+
else:
|
|
251
|
+
value = opts[key]
|
|
252
|
+
|
|
253
|
+
if type(value) == str:
|
|
254
|
+
value = shlex.quote(value)
|
|
255
|
+
|
|
256
|
+
result.append('--%s %s' % (key, value))
|
|
257
|
+
|
|
258
|
+
result = ' '.join(result)
|
|
259
|
+
|
|
260
|
+
return result
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
# Parsing of DATASEC-like keywords
|
|
264
|
+
def parse_det(string):
|
|
265
|
+
"""
|
|
266
|
+
Parse DATASEC-like keyword
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
x0, x1, y0, y1 = [int(_) - 1 for _ in sum([_.split(':') for _ in string[1:-1].split(',')], [])]
|
|
270
|
+
|
|
271
|
+
return x0, x1, y0, y1
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# Cropping of overscans if any
|
|
275
|
+
def crop_overscans(image, header, subtract_bias=True, verbose=False):
|
|
276
|
+
"""
|
|
277
|
+
Crop overscans from input image based on its header keywords.
|
|
278
|
+
Also, subtract the 'bias' value estimated from overscan.
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
# Simple wrapper around print for logging in verbose mode only
|
|
282
|
+
log = (verbose if callable(verbose) else print) if verbose else lambda *args, **kwargs: None
|
|
283
|
+
|
|
284
|
+
if header is not None:
|
|
285
|
+
header = header.copy()
|
|
286
|
+
|
|
287
|
+
bias = 0
|
|
288
|
+
|
|
289
|
+
for kw in ['BIASSEC']:
|
|
290
|
+
if kw in header:
|
|
291
|
+
x1, x2, y1, y2 = parse_det(header.get(kw))
|
|
292
|
+
biasimg = image[y1 : y2 + 1, x1 : x2 + 1]
|
|
293
|
+
|
|
294
|
+
bias = np.mean(biasimg)
|
|
295
|
+
log('Estimated bias level using %s: %s = %.2f' % (kw, header.get(kw), bias))
|
|
296
|
+
|
|
297
|
+
for kw in ['TRIMSEC', 'DATASEC']:
|
|
298
|
+
if kw in header:
|
|
299
|
+
x1, x2, y1, y2 = parse_det(header.get(kw))
|
|
300
|
+
|
|
301
|
+
if header is not None and header.get('CRPIX1') is not None:
|
|
302
|
+
header['CRPIX1'] -= x1
|
|
303
|
+
header['CRPIX2'] -= y1
|
|
304
|
+
|
|
305
|
+
image = image[y1 : y2 + 1, x1 : x2 + 1]
|
|
306
|
+
log('Cropped image using %s: %s' % (kw, header.get(kw)))
|
|
307
|
+
|
|
308
|
+
break
|
|
309
|
+
|
|
310
|
+
for kw in ['BIASSEC', 'TRIMSEC', 'DATASEC']:
|
|
311
|
+
if kw in header:
|
|
312
|
+
header[kw + '0'] = header.pop(kw)
|
|
313
|
+
|
|
314
|
+
image -= bias
|
|
315
|
+
|
|
316
|
+
return image, header
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# Simple 2D rebinning
|
|
320
|
+
def rebin_image(image, nx=1, ny=None):
|
|
321
|
+
"""
|
|
322
|
+
Simple rebinning / downscaling the image by an integer factor.
|
|
323
|
+
Pixel values are averaged, not co-added.
|
|
324
|
+
"""
|
|
325
|
+
if ny is None:
|
|
326
|
+
ny = nx
|
|
327
|
+
shape = (image.shape[0] // ny, ny, image.shape[1] // nx, nx)
|
|
328
|
+
return image.reshape(shape).mean(-1).mean(1)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# Simple writing of some data to file
|
|
332
|
+
def file_write(filename, contents=None, append=False):
|
|
333
|
+
"""
|
|
334
|
+
Simple utility for writing some contents into file.
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
with open(filename, 'a' if append else 'w') as f:
|
|
338
|
+
if contents is not None:
|
|
339
|
+
f.write(contents)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# Simple reading of data from file
|
|
343
|
+
def file_read(filename, contents=None):
|
|
344
|
+
"""
|
|
345
|
+
Simple utility for reading some contents from file.
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
if os.path.exists(filename):
|
|
349
|
+
with open(filename, 'r') as f:
|
|
350
|
+
return f.read()
|
|
351
|
+
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# Writing of FITS-compressed files
|
|
356
|
+
def fits_write(filename, image, header=None, compress=False):
|
|
357
|
+
"""
|
|
358
|
+
Store image with or without header to FITS file, with or without compression
|
|
359
|
+
"""
|
|
360
|
+
if compress:
|
|
361
|
+
hdu = fits.CompImageHDU(image, header)
|
|
362
|
+
else:
|
|
363
|
+
hdu = fits.PrimaryHDU(image, header)
|
|
364
|
+
|
|
365
|
+
hdu.writeto(filename, overwrite=True)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stdpipe
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Simple Transient Detection Pipeline
|
|
5
|
+
Author-email: Sergey Karpov <karpov.sv@gmail.com>
|
|
6
|
+
Maintainer-email: Sergey Karpov <karpov.sv@gmail.com>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2022 Sergey Karpov
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Homepage, https://github.com/karpov-sv/stdpipe
|
|
30
|
+
Project-URL: Documentation, https://stdpipe.readthedocs.io/
|
|
31
|
+
Project-URL: Repository, https://github.com/karpov-sv/stdpipe
|
|
32
|
+
Project-URL: Bug Tracker, https://github.com/karpov-sv/stdpipe/issues
|
|
33
|
+
Project-URL: Changelog, https://github.com/karpov-sv/stdpipe/commits/master
|
|
34
|
+
Keywords: astronomy,astrophysics,transients,photometry,astrometry,image-processing,pipeline
|
|
35
|
+
Classifier: Development Status :: 4 - Beta
|
|
36
|
+
Classifier: Intended Audience :: Science/Research
|
|
37
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
38
|
+
Classifier: Operating System :: OS Independent
|
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
46
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
47
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
48
|
+
Requires-Python: >=3.8
|
|
49
|
+
Description-Content-Type: text/markdown
|
|
50
|
+
License-File: LICENSE.md
|
|
51
|
+
Requires-Dist: numpy
|
|
52
|
+
Requires-Dist: scipy
|
|
53
|
+
Requires-Dist: astropy>=4.1
|
|
54
|
+
Requires-Dist: matplotlib
|
|
55
|
+
Requires-Dist: astroquery>0.4.1
|
|
56
|
+
Requires-Dist: sep-x
|
|
57
|
+
Requires-Dist: astroscrappy
|
|
58
|
+
Requires-Dist: photutils>=2.2
|
|
59
|
+
Requires-Dist: scikit-image>=0.22.0
|
|
60
|
+
Requires-Dist: statsmodels
|
|
61
|
+
Requires-Dist: tqdm
|
|
62
|
+
Requires-Dist: regions
|
|
63
|
+
Requires-Dist: python-dateutil
|
|
64
|
+
Requires-Dist: requests
|
|
65
|
+
Requires-Dist: pyfftw
|
|
66
|
+
Requires-Dist: scikit-learn
|
|
67
|
+
Provides-Extra: dev
|
|
68
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
69
|
+
Requires-Dist: pytest-cov>=2.10; extra == "dev"
|
|
70
|
+
Requires-Dist: pytest-xdist>=2.0; extra == "dev"
|
|
71
|
+
Requires-Dist: pytest-mock>=3.0; extra == "dev"
|
|
72
|
+
Requires-Dist: pytest-timeout>=2.0; extra == "dev"
|
|
73
|
+
Requires-Dist: pytest-benchmark>=3.4; extra == "dev"
|
|
74
|
+
Requires-Dist: hypothesis>=6.0; extra == "dev"
|
|
75
|
+
Provides-Extra: docs
|
|
76
|
+
Requires-Dist: sphinx>=4.0; extra == "docs"
|
|
77
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
78
|
+
Requires-Dist: sphinx-math-dollar; extra == "docs"
|
|
79
|
+
Requires-Dist: numpydoc; extra == "docs"
|
|
80
|
+
Requires-Dist: myst-parser; extra == "docs"
|
|
81
|
+
Requires-Dist: sphinxcontrib-apidoc; extra == "docs"
|
|
82
|
+
Requires-Dist: sphinx-prompt; extra == "docs"
|
|
83
|
+
Provides-Extra: adaptive
|
|
84
|
+
Requires-Dist: powerbin; extra == "adaptive"
|
|
85
|
+
Provides-Extra: ml
|
|
86
|
+
Requires-Dist: tensorflow<2.20,>=2.10; extra == "ml"
|
|
87
|
+
Provides-Extra: all
|
|
88
|
+
Requires-Dist: stdpipe[adaptive,dev,docs,ml]; extra == "all"
|
|
89
|
+
Dynamic: license-file
|
|
90
|
+
|
|
91
|
+
# STDPipe - Simple Transient Detection Pipeline
|
|
92
|
+
*AKA: random codes noone else will ever use*
|
|
93
|
+
|
|
94
|
+
*STDPipe* is a set of Python routines for astrometry, photometry and transient detection related tasks, intended for quick and easy implementation of custom pipelines, as well as for interactive data analysis.
|
|
95
|
+
|
|
96
|
+
### Design principles
|
|
97
|
+
- implemented as a library of routines covering most common tasks
|
|
98
|
+
- operates on standard Python objects: NumPy arrays for images, Astropy Tables for catalogs and object lists, etc
|
|
99
|
+
- does not try to re-implement the things already implemented in other Python packages
|
|
100
|
+
- conveniently wraps external codes that do not have their own Python interfaces (*SExtractor*, *SCAMP*, *PSFEx*, *HOTPANTS*, *Astrometry.Net*, ...)
|
|
101
|
+
- wrapping is transparent: all data passed from Python, all options customizable from Python, all (or most of) outputs available back
|
|
102
|
+
- everything operates on temporary files, nothing is kept after the run unless explicitly asked for
|
|
103
|
+
|
|
104
|
+
### Features
|
|
105
|
+
- ~~pre-processing~~ - should be handled before in an instrument-specific way
|
|
106
|
+
- bias/dark subtraction, flatfielding, masking
|
|
107
|
+
- object detection and photometry
|
|
108
|
+
- SExtractor, SEP, or photutils (pure Python) for detection
|
|
109
|
+
- aperture, optimal extraction (Naylor 1998), and PSF fitting photometry
|
|
110
|
+
- grouped fitting for crowded fields
|
|
111
|
+
- astrometric calibration
|
|
112
|
+
- Astrometry.Net for blind WCS solving
|
|
113
|
+
- quad-hash pattern matching for refinement (pure Python, no external deps, default method)
|
|
114
|
+
- SCAMP or Astropy-based code for refinement (alternative)
|
|
115
|
+
- photometric calibration
|
|
116
|
+
- Vizier catalogues, passband conversion (PS1 to Johnson, Gaia to Johnson, ...)
|
|
117
|
+
- spatial polynomial + color term + intrinsic scatter
|
|
118
|
+
- image reprojection and stacking
|
|
119
|
+
- Lanczos interpolation with automatic oversampling and flux conservation (pure Python, default)
|
|
120
|
+
- SWarp wrapper (alternative)
|
|
121
|
+
- image subtraction
|
|
122
|
+
- HiPS templates
|
|
123
|
+
- PanSTARRS DR1 or Legacy Survey templates
|
|
124
|
+
- HOTPANTS + custom noise model
|
|
125
|
+
- ZOGY
|
|
126
|
+
- transient detection and classification
|
|
127
|
+
- noise-weighted detection, cutout adjustment, ...
|
|
128
|
+
- feature-based real/bogus classification (no TensorFlow required)
|
|
129
|
+
- CNN-based real/bogus classification (optional, requires TensorFlow)
|
|
130
|
+
- auxiliary functions
|
|
131
|
+
- PSF estimation, simulated stars, FITS header utilities, plotting, ...
|
|
132
|
+
- light curve creation (soon)
|
|
133
|
+
- spatial clustering, color regression, variability analysis, ...
|
|
134
|
+
|
|
135
|
+
# Installation
|
|
136
|
+
|
|
137
|
+
*STDpipe* is available at https://github.com/karpov-sv/stdpipe and is mirrored at https://gitlab.in2p3.fr/icare/stdpipe
|
|
138
|
+
|
|
139
|
+
The package is in constant development, so to keep track of the changes the suggested way of installing it is by cloning the repository
|
|
140
|
+
```
|
|
141
|
+
git clone https://github.com/karpov-sv/stdpipe.git
|
|
142
|
+
```
|
|
143
|
+
and then installing from it in development (or "editable") mode by running the command
|
|
144
|
+
```
|
|
145
|
+
cd stdpipe
|
|
146
|
+
python3 -m pip install -e .
|
|
147
|
+
```
|
|
148
|
+
This way you may update the repository or apply local patches, and it will immediately be reflected in the installed package.
|
|
149
|
+
|
|
150
|
+
Apart of Python requirements that will be installed automatically, *STDPipe* also (optionally) makes use of the following external software:
|
|
151
|
+
- [SExtractor](https://github.com/astromatic/sextractor)
|
|
152
|
+
- [SCAMP](https://github.com/astromatic/scamp)
|
|
153
|
+
- [PSFEx](https://github.com/astromatic/psfex)
|
|
154
|
+
- [SWarp](https://github.com/astromatic/swarp)
|
|
155
|
+
- [HOTPANTS](https://github.com/acbecker/hotpants)
|
|
156
|
+
- [Astrometry.Net](https://github.com/dstndstn/astrometry.net)
|
|
157
|
+
|
|
158
|
+
Most of them may be installed from your package manager. E.g. on Debian or Ubuntu systems it may look like that:
|
|
159
|
+
```
|
|
160
|
+
sudo apt install sextractor scamp psfex swarp
|
|
161
|
+
```
|
|
162
|
+
or, on Miniconda/Anaconda, like that:
|
|
163
|
+
```
|
|
164
|
+
conda install -c conda-forge astromatic-source-extractor astromatic-scamp astromatic-psfex astromatic-swarp
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
You may also check more detailed installation instructions [here](https://stdpipe.readthedocs.io/en/latest/installation.html).
|
|
168
|
+
|
|
169
|
+
# Usage
|
|
170
|
+
|
|
171
|
+
Please consult the [documentation for *STDPipe*](https://stdpipe.readthedocs.io/) for the basic usage patterns and description of its API. You may check the examples inside [notebooks/](notebooks/) folder, especially the [tutorial](notebooks/stdpipe_tutorial.ipynb) that demonstrates basic steps of a typical image processing.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
stdpipe/__init__.py,sha256=6ZJ6LfuhuURE18kIKKOkR6El1Re1GBaGT3OXIKVmL34,289
|
|
2
|
+
stdpipe/artefacts.py,sha256=ON_cFLluXY58H-YsoDORIzByjRGH3La8yVGVwUUQjyg,12934
|
|
3
|
+
stdpipe/astrometry.py,sha256=ieaPysfyHQSCiYV9FGjdmt13ErdRNC09K24l4KcYMdw,68386
|
|
4
|
+
stdpipe/astrometry_quad.py,sha256=vyrd-6E9knTquwW_kvPblVmuyjlyvB1lkMkCtEDx2tM,62011
|
|
5
|
+
stdpipe/astrometry_wcs.py,sha256=mQllKUG_x2qYeeHZPvKwxHVDJE2M9k3uAzyQQ7Fndps,40720
|
|
6
|
+
stdpipe/catalogs.py,sha256=mHL-ZW8ocqKdlfHqszj-u8CYK7HcJa9zYcwJYfxGNZ0,33628
|
|
7
|
+
stdpipe/cutouts.py,sha256=otYUsUDsEgtGc4EYZz9we4sCbofOETirxQghHCX7y6I,17717
|
|
8
|
+
stdpipe/db.py,sha256=hosPbMp7ugAw8WuQIr4sBITb-tqL8neQ-dnhkhbx7hU,4724
|
|
9
|
+
stdpipe/fringe_removal.py,sha256=TFbX0OY4xwPGIf3rfcWkV5jpvW0OLVgBzpo326WMKpg,39955
|
|
10
|
+
stdpipe/lcs.py,sha256=-oNlk6GjfRcFYCkAX87b_gijBLKb4mACJ6ZOEhPamL0,16272
|
|
11
|
+
stdpipe/photometry.py,sha256=a6L6pTVx0lBt2LOS3vetlKitSwFqCPkOZOTY3i4yKho,83110
|
|
12
|
+
stdpipe/photometry_background.py,sha256=7KsM6xSH2ZF-V6V2Y5vK20Kci2SmCv-p25pdxPz5v0k,36502
|
|
13
|
+
stdpipe/photometry_iraf.py,sha256=DU0XQR5JkpGSck1OeuaTr5ljR4fHpspDo3WAewtdyR8,31834
|
|
14
|
+
stdpipe/photometry_measure.py,sha256=sGaq2sqw7eKEm2fnCJX88gjF7Pe5tdtns8CtnetO9HA,84974
|
|
15
|
+
stdpipe/photometry_model.py,sha256=usBVJtqSX8dpeOVf4eNFbkrv41U7BhiXYP3uZY5zHto,31791
|
|
16
|
+
stdpipe/photometry_psf.py,sha256=sQTHl-810CogKLhvN7eThiVE_QIG9V3-YPsmmmJP9fU,45975
|
|
17
|
+
stdpipe/photometry_quality.py,sha256=8Qr706ysGDGm66tKzEb2JJdFMD0OWJEzjzJkG2BoXE0,7023
|
|
18
|
+
stdpipe/pipeline.py,sha256=bM4v1xtj7kKjeb_czn1Q-5qxYzV4onFLqisaA8Gw1VY,43915
|
|
19
|
+
stdpipe/plots.py,sha256=J0D6_041mpg3UrKZnHyP8hBSOrqtiNdL0TxvP37FLUg,51250
|
|
20
|
+
stdpipe/psf.py,sha256=ml6IF3cv78nT-9qNjYt_8Q5j_EgajAFqn1dUdVPgYW8,56236
|
|
21
|
+
stdpipe/realbogus.py,sha256=LWP1mDXPxmPEa9sMK88DVNxKW-qRB1u0sgFK3xsvbdo,31583
|
|
22
|
+
stdpipe/realbogus_features.py,sha256=bbMQ9WCb4gxjelTmZMn5T2G5ALJpcrpZir2ihtbzqoc,53824
|
|
23
|
+
stdpipe/reproject.py,sha256=cU7HmpBQfF85_9Qm7hq63BBb4amnefU_YsQqmffip5A,31913
|
|
24
|
+
stdpipe/resolve.py,sha256=IQr_4zn89l54s88iNjojI0lP9zsKfrrWkhdPCnc7GF8,8990
|
|
25
|
+
stdpipe/sfft.py,sha256=x_QV-oknIGG0QAdk4VeeESahOXUXoRvjv0JinpZq0IU,41082
|
|
26
|
+
stdpipe/simulation.py,sha256=dplowLWkrHCxTjZrM4WYEEdTbf4g79mZTgn2mHKnPVU,72354
|
|
27
|
+
stdpipe/smoothing.py,sha256=lVLjWiKVX07bKsnLIO2LAQ-7MoPKlxi5GpcLa1YMKPc,19130
|
|
28
|
+
stdpipe/subtraction.py,sha256=pSd_hjvNJMXp-qtqBigHnrHvFtqze7hzKw8UVMLglm8,49582
|
|
29
|
+
stdpipe/templates.py,sha256=oX2rXuT7uHN_KYzSvjiAM6iN-gArUh2W3YxIJX0r-WM,31008
|
|
30
|
+
stdpipe/utils.py,sha256=9ZSu1xjqs9VgIdNolrI39Ls84DUf6MXprsHCTT4ynDw,11131
|
|
31
|
+
stdpipe/data/legacysurvey_bricks.fits.gz,sha256=Rq6DSn5g0ZXJiGKKDUyx9C82cb_KCSq2aNMcKjGwEJ8,4254781
|
|
32
|
+
stdpipe/data/ps1skycells.txt,sha256=lZkykMWXRxuNBMOI3kwjAQYFem7ddioG2LOIx-5Y0Ms,8972943
|
|
33
|
+
stdpipe-0.4.0.dist-info/licenses/LICENSE.md,sha256=sTpMtA36_ilynqyuY9sLiCp4pN6xNfIyQrDID5wjjj4,1070
|
|
34
|
+
stdpipe-0.4.0.dist-info/METADATA,sha256=9zNh8yzkK0WyBIj1EFzywhzxNuj5RCoqTZ7Npe2cKd0,8350
|
|
35
|
+
stdpipe-0.4.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
36
|
+
stdpipe-0.4.0.dist-info/top_level.txt,sha256=f3r9hh1IEMpDvQFYBm00aH73Fp9QPcUOYQpQBeyxaas,8
|
|
37
|
+
stdpipe-0.4.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Sergey Karpov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
stdpipe
|