rms-starcat 0.0.1__py3-none-any.whl → 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rms-starcat might be problematic. Click here for more details.
- rms_starcat-1.0.1.dist-info/METADATA +154 -0
- rms_starcat-1.0.1.dist-info/RECORD +12 -0
- {rms_starcat-0.0.1.dist-info → rms_starcat-1.0.1.dist-info}/WHEEL +1 -1
- starcat/__init__.py +24 -5
- starcat/_version.py +9 -4
- starcat/py.typed +0 -0
- starcat/spice.py +72 -75
- starcat/starcatalog.py +280 -172
- starcat/ucac4.py +321 -258
- starcat/ybsc.py +313 -185
- rms_starcat-0.0.1.dist-info/METADATA +0 -39
- rms_starcat-0.0.1.dist-info/RECORD +0 -11
- {rms_starcat-0.0.1.dist-info → rms_starcat-1.0.1.dist-info/licenses}/LICENSE +0 -0
- {rms_starcat-0.0.1.dist-info → rms_starcat-1.0.1.dist-info}/top_level.txt +0 -0
starcat/ucac4.py
CHANGED
|
@@ -2,138 +2,237 @@
|
|
|
2
2
|
# starcat/ucac4.py
|
|
3
3
|
################################################################################
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Zacharias, N. et al. 2013, The Astronomical Journal, 145, 44
|
|
6
6
|
|
|
7
|
-
from __future__ import
|
|
7
|
+
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
except ImportError:
|
|
12
|
-
from .starcatalog import *
|
|
13
|
-
import numpy as np
|
|
14
|
-
import os.path
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
15
11
|
import struct
|
|
12
|
+
from typing import Any, Iterator, Optional, cast
|
|
13
|
+
|
|
14
|
+
from filecache import FCPath
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from .starcatalog import (HALFPI,
|
|
18
|
+
MAS_TO_RAD,
|
|
19
|
+
YEAR_TO_SEC,
|
|
20
|
+
Star,
|
|
21
|
+
StarCatalog
|
|
22
|
+
)
|
|
16
23
|
|
|
17
|
-
UCAC4_OBJ_TYPE_CLEAN = 0
|
|
18
|
-
UCAC4_OBJ_TYPE_NEAR_OVEREXPOSED = 1
|
|
19
|
-
UCAC4_OBJ_TYPE_STREAK = 2
|
|
20
|
-
UCAC4_OBJ_TYPE_HPM = 3
|
|
21
|
-
UCAC4_OBJ_TYPE_EXT_HPM = 4
|
|
22
|
-
UCAC4_OBJ_TYPE_POOR_PM = 5
|
|
23
|
-
UCAC4_OBJ_TYPE_SUBST_ASTROMETRY = 6
|
|
24
|
-
UCAC4_OBJ_TYPE_SUPPL = 7
|
|
25
|
-
UCAC4_OBJ_TYPE_HPM_NOT_MATCHED = 8
|
|
26
|
-
UCAC4_OBJ_TYPE_HPM_DISCREPANT = 9
|
|
27
|
-
|
|
28
|
-
UCAC4_OBJ_TYPE_STRINGS = ['CLEAN', 'NEAR_OVEREXPOSED', 'STREAK', 'HPM',
|
|
29
|
-
'EXT_HPM', 'POOR_PM', 'SUBST_ASTROMETRY', 'SUPPL',
|
|
30
|
-
'HPM_NOT_MATCHED', 'HPM_DISCREPANT']
|
|
31
|
-
|
|
32
|
-
#CATMATCH_TYCHO = 0
|
|
33
|
-
#CATMATCH_AC2000 = 1
|
|
34
|
-
#CATMATCH_AGK2_BONN = 2
|
|
35
|
-
#CATMATCH_AGK2_HAMBURG = 3
|
|
36
|
-
#CATMATCH_ZONE_ASTROGRAPH = 4
|
|
37
|
-
#CATMATCH_BLACK_BIRCH = 5
|
|
38
|
-
#CATMATCH_LICK_ASTROGRAPH = 6
|
|
39
|
-
#CATMATCH_NPM_LICK = 7
|
|
40
|
-
#CATMATCH_SPM_YSJ1 = 8
|
|
41
|
-
|
|
42
|
-
UCAC4_DOUBLE_STAR_FLAG_SINGLE = 0
|
|
43
|
-
UCAC4_DOUBLE_STAR_FLAG_COMP1 = 1
|
|
44
|
-
UCAC4_DOUBLE_STAR_FLAG_COMP2 = 2
|
|
45
|
-
UCAC4_DOUBLE_STAR_FLAG_BLENDED = 3
|
|
46
|
-
|
|
47
|
-
UCAC4_DOUBLE_STAR_FLAG_STRINGS = ['SINGLE', 'COMP1', 'COMP2', 'BLENDED']
|
|
48
|
-
|
|
49
|
-
UCAC4_DOUBLE_STAR_TYPE_NONE = 0
|
|
50
|
-
UCAC4_DOUBLE_STAR_TYPE_1PEAK = 1
|
|
51
|
-
UCAC4_DOUBLE_STAR_TYPE_2PEAK = 2
|
|
52
|
-
UCAC4_DOUBLE_STAR_TYPE_SECONDARY_PEAK = 3
|
|
53
|
-
UCAC4_DOUBLE_STAR_TYPE_1PEAK_FIT = 4
|
|
54
|
-
UCAC4_DOUBLE_STAR_TYPE_2PEAK_FIT = 5
|
|
55
|
-
UCAC4_DOUBLE_STAR_TYPE_SECONDARY_PEAK_FIT = 6
|
|
56
|
-
|
|
57
|
-
UCAC4_DOUBLE_STAR_TYPE_STRINGS = ['NONE', '1PEAK', '2PEAK', 'SECONDARY_PEAK',
|
|
58
|
-
'1PEAK_FIT', '2PEAK_FIT',
|
|
59
|
-
'SECONDARY_PEAK_FIT']
|
|
60
24
|
|
|
61
25
|
class UCAC4Star(Star):
|
|
62
26
|
"""A holder for star attributes.
|
|
63
27
|
|
|
64
28
|
This class includes attributes unique to the UCAC4 catalog."""
|
|
65
29
|
|
|
66
|
-
|
|
30
|
+
UCAC4_OBJ_TYPE_CLEAN = 0
|
|
31
|
+
UCAC4_OBJ_TYPE_NEAR_OVEREXPOSED = 1
|
|
32
|
+
UCAC4_OBJ_TYPE_STREAK = 2
|
|
33
|
+
UCAC4_OBJ_TYPE_HPM = 3
|
|
34
|
+
UCAC4_OBJ_TYPE_EXT_HPM = 4
|
|
35
|
+
UCAC4_OBJ_TYPE_POOR_PM = 5
|
|
36
|
+
UCAC4_OBJ_TYPE_SUBST_ASTROMETRY = 6
|
|
37
|
+
UCAC4_OBJ_TYPE_SUPPL = 7
|
|
38
|
+
UCAC4_OBJ_TYPE_HPM_NOT_MATCHED = 8
|
|
39
|
+
UCAC4_OBJ_TYPE_HPM_DISCREPANT = 9
|
|
40
|
+
|
|
41
|
+
UCAC4_OBJ_TYPE_STRINGS = ['CLEAN', 'NEAR_OVEREXPOSED', 'STREAK', 'HPM',
|
|
42
|
+
'EXT_HPM', 'POOR_PM', 'SUBST_ASTROMETRY', 'SUPPL',
|
|
43
|
+
'HPM_NOT_MATCHED', 'HPM_DISCREPANT']
|
|
44
|
+
|
|
45
|
+
#CATMATCH_TYCHO = 0
|
|
46
|
+
#CATMATCH_AC2000 = 1
|
|
47
|
+
#CATMATCH_AGK2_BONN = 2
|
|
48
|
+
#CATMATCH_AGK2_HAMBURG = 3
|
|
49
|
+
#CATMATCH_ZONE_ASTROGRAPH = 4
|
|
50
|
+
#CATMATCH_BLACK_BIRCH = 5
|
|
51
|
+
#CATMATCH_LICK_ASTROGRAPH = 6
|
|
52
|
+
#CATMATCH_NPM_LICK = 7
|
|
53
|
+
#CATMATCH_SPM_YSJ1 = 8
|
|
54
|
+
|
|
55
|
+
UCAC4_DOUBLE_STAR_FLAG_SINGLE = 0
|
|
56
|
+
UCAC4_DOUBLE_STAR_FLAG_COMP1 = 1
|
|
57
|
+
UCAC4_DOUBLE_STAR_FLAG_COMP2 = 2
|
|
58
|
+
UCAC4_DOUBLE_STAR_FLAG_BLENDED = 3
|
|
59
|
+
|
|
60
|
+
UCAC4_DOUBLE_STAR_FLAG_STRINGS = ['SINGLE', 'COMP1', 'COMP2', 'BLENDED']
|
|
61
|
+
|
|
62
|
+
UCAC4_DOUBLE_STAR_TYPE_NONE = 0
|
|
63
|
+
UCAC4_DOUBLE_STAR_TYPE_1PEAK = 1
|
|
64
|
+
UCAC4_DOUBLE_STAR_TYPE_2PEAK = 2
|
|
65
|
+
UCAC4_DOUBLE_STAR_TYPE_SECONDARY_PEAK = 3
|
|
66
|
+
UCAC4_DOUBLE_STAR_TYPE_1PEAK_FIT = 4
|
|
67
|
+
UCAC4_DOUBLE_STAR_TYPE_2PEAK_FIT = 5
|
|
68
|
+
UCAC4_DOUBLE_STAR_TYPE_SECONDARY_PEAK_FIT = 6
|
|
69
|
+
|
|
70
|
+
UCAC4_DOUBLE_STAR_TYPE_STRINGS = ['NONE', '1PEAK', '2PEAK', 'SECONDARY_PEAK',
|
|
71
|
+
'1PEAK_FIT', '2PEAK_FIT',
|
|
72
|
+
'SECONDARY_PEAK_FIT']
|
|
73
|
+
|
|
74
|
+
def __init__(self) -> None:
|
|
67
75
|
# Initialize the standard fields
|
|
68
|
-
|
|
76
|
+
super().__init__()
|
|
69
77
|
|
|
70
78
|
# Initialize the UCAC4-specific fields
|
|
71
|
-
self.vmag_model = None
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
self.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
self.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
self.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
79
|
+
self.vmag_model: Optional[float] = None
|
|
80
|
+
"""Fit model magnitude"""
|
|
81
|
+
|
|
82
|
+
self.obj_type: Optional[int] = None
|
|
83
|
+
"""The object type used to identify possible problems with a star or
|
|
84
|
+
the source of data:
|
|
85
|
+
0 = good, clean star (from MPOS), no known problem;
|
|
86
|
+
1 = largest flag of any image = near overexposed star (from MPOS);
|
|
87
|
+
2 = largest flag of any image = possible streak object (from MPOS);
|
|
88
|
+
3 = high proper motion (HPM) star, match with external PM file (MPOS);
|
|
89
|
+
4 = actually use external HPM data instead of UCAC4 observ.data
|
|
90
|
+
(accuracy of positions varies between catalogs);
|
|
91
|
+
5 = poor proper motion solution, report only CCD epoch position;
|
|
92
|
+
6 = substitute poor astrometric results by FK6/Hip/Tycho-2 data;
|
|
93
|
+
7 = added supplement star (no CCD data) from FK6/Hip/Tycho-2 data,
|
|
94
|
+
and 2 stars added from high proper motion surveys;
|
|
95
|
+
8 = high proper motion solution in UCAC4, star not matched with PPMXL;
|
|
96
|
+
9 = high proper motion solution in UCAC4, discrepant PM to PPMXL
|
|
97
|
+
(see discussion of flags 8,9 in redcution section 2e above)
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
self.double_star_flag: Optional[bool] = None
|
|
101
|
+
"""Double star flag overall classification:
|
|
102
|
+
0 = single star;
|
|
103
|
+
1 = component #1 of "good" double star;
|
|
104
|
+
2 = component #2 of "good" double star;
|
|
105
|
+
3 = blended image
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
self.double_star_type: Optional[int] = None
|
|
109
|
+
"""Double star type:
|
|
110
|
+
0 = no double star, not sufficient #pixels or elongation
|
|
111
|
+
to even call double star fit subroutine;
|
|
112
|
+
1 = elongated image but no more than 1 peak detected;
|
|
113
|
+
2 = 2 separate peaks detected -> try double star fit;
|
|
114
|
+
3 = secondary peak found on each side of primary;
|
|
115
|
+
4 = case 1 after successful double fit (small separ. blended image);
|
|
116
|
+
5 = case 2 after successful double fit (most likely real double);
|
|
117
|
+
6 = case 3 after successful double fit (brighter secondary picked)
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
self.galaxy_match: Optional[float] = None
|
|
121
|
+
"""LEDA galaxy match flag:
|
|
122
|
+
This flag is either 0 (no match) or contains the log10 of
|
|
123
|
+
the apparent total diameter for I-band (object size) information
|
|
124
|
+
(unit = 0.1 arcmin) copied from the LEDA catalog (galaxies).
|
|
125
|
+
A size value of less than 1 has been rounded up to 1.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
self.extended_source: Optional[bool] = None
|
|
129
|
+
"""2MASS extended source flag:
|
|
130
|
+
This flag is either 0 (no match) or contains the length of
|
|
131
|
+
the semi-major axis of the fiducial ellipse at the K-band
|
|
132
|
+
(object size) information copied from the 2MASS extended source
|
|
133
|
+
catalog.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
self.num_img_total: Optional[int] = None
|
|
137
|
+
"""Total # of CCD images of this star"""
|
|
138
|
+
|
|
139
|
+
self.num_img_used: Optional[int] = None
|
|
140
|
+
"""# of CCD images used for this star.
|
|
141
|
+
A zero for the number of used images indicates that all images
|
|
142
|
+
have some "problem" (such as overexposure). In that case an unweighted
|
|
143
|
+
mean over all available images (na) is taken to derive the mean
|
|
144
|
+
position, while normally a weighted mean was calculated based on
|
|
145
|
+
the "good" images, excluding possible problem images (nu <= na).
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
self.num_cat_pm: Optional[int] = None
|
|
149
|
+
"""# catalogs (epochs) used for proper motions"""
|
|
150
|
+
|
|
151
|
+
self.ra_mean_epoch: Optional[float] = None
|
|
152
|
+
"""Central epoch for mean RA, minus 1900"""
|
|
153
|
+
|
|
154
|
+
self.dec_mean_epoch: Optional[int] = None
|
|
155
|
+
"""Central epoch for mean Dec, minus 1900"""
|
|
156
|
+
|
|
157
|
+
self.cat_match: Optional[list[int]] = None
|
|
158
|
+
"""A list of ints indicating which catalogs this star has matched against.
|
|
159
|
+
There are 10 entries: Yale SPM, FK6-Hipparcos-Tycho, AC2000, AGK2 Bonn,
|
|
160
|
+
AKG2 Hamburg, Zone Astrog., Black Birch, Lick Astrog., NPM Lick, and
|
|
161
|
+
SPM YSJ1. See the comments in this file for more details.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
self.apass_mag_b: Optional[float] = None
|
|
165
|
+
"""B magnitude from APASS"""
|
|
166
|
+
|
|
167
|
+
self.apass_mag_v: Optional[float] = None
|
|
168
|
+
"""V magnitude from APASS"""
|
|
169
|
+
|
|
170
|
+
self.apass_mag_g: Optional[float] = None
|
|
171
|
+
"""G magnitude from APASS"""
|
|
172
|
+
|
|
173
|
+
self.apass_mag_r: Optional[float] = None
|
|
174
|
+
"""R magnitude from APASS"""
|
|
175
|
+
|
|
176
|
+
self.apass_mag_i: Optional[float] = None
|
|
177
|
+
"""I magnitude from APASS"""
|
|
178
|
+
|
|
179
|
+
self.apass_mag_b_sigma: Optional[float] = None
|
|
180
|
+
"""Uncertainty of B magnitude from APASS"""
|
|
181
|
+
|
|
182
|
+
self.apass_mag_v_sigma: Optional[float] = None
|
|
183
|
+
"""Uncertainty of V magnitude from APASS"""
|
|
184
|
+
|
|
185
|
+
self.apass_mag_g_sigma: Optional[float] = None
|
|
186
|
+
"""Uncertainty of G magnitude from APASS"""
|
|
187
|
+
|
|
188
|
+
self.apass_mag_r_sigma: Optional[float] = None
|
|
189
|
+
"""Uncertainty of R magnitude from APASS"""
|
|
190
|
+
|
|
191
|
+
self.apass_mag_i_sigma: Optional[float] = None
|
|
192
|
+
"""Uncertainty of I magnitude from APASS"""
|
|
193
|
+
|
|
194
|
+
self.johnson_mag_b: Optional[float] = None
|
|
195
|
+
"""The Johnson B magnitude derived from APASS measurements."""
|
|
196
|
+
|
|
197
|
+
self.johnson_mag_v: Optional[float] = None
|
|
198
|
+
"""The Johnson V magnitude derived from APASS measurements."""
|
|
199
|
+
|
|
200
|
+
self.id_str: Optional[str] = None
|
|
201
|
+
"""A unique name indicating the position in the UCAC4 catalog"""
|
|
202
|
+
|
|
203
|
+
self.id_str_ucac2: Optional[str] = None
|
|
204
|
+
"""A unique name indicating the position in the UCAC2 catalog"""
|
|
205
|
+
|
|
206
|
+
def __str__(self) -> str:
|
|
207
|
+
|
|
104
208
|
ret = Star.__str__(self)
|
|
105
209
|
|
|
106
210
|
ret += 'OBJTYPE '
|
|
107
211
|
if self.obj_type is None:
|
|
108
212
|
ret += 'None'
|
|
109
213
|
else:
|
|
110
|
-
ret += UCAC4_OBJ_TYPE_STRINGS[self.obj_type]
|
|
214
|
+
ret += UCAC4Star.UCAC4_OBJ_TYPE_STRINGS[self.obj_type]
|
|
111
215
|
ret += ' | '
|
|
112
216
|
|
|
113
217
|
if self.vmag_model is None:
|
|
114
218
|
ret += 'APER VMAG None'
|
|
115
219
|
else:
|
|
116
|
-
ret += 'APER VMAG
|
|
220
|
+
ret += f'APER VMAG {self.vmag_model:6.3f}'
|
|
117
221
|
ret += ' | '
|
|
118
222
|
|
|
119
|
-
if self.temperature is None:
|
|
120
|
-
ret += 'TEMP None'
|
|
121
|
-
else:
|
|
122
|
-
ret += 'TEMP %5d' % (self.temperature)
|
|
123
|
-
ret += ' | SCLASS %2s' % (str(self.spectral_class))
|
|
124
223
|
ret += '\n'
|
|
125
224
|
|
|
126
225
|
ret += 'DBL STAR FLAG='
|
|
127
226
|
if self.double_star_flag is None:
|
|
128
227
|
ret += 'None'
|
|
129
228
|
else:
|
|
130
|
-
ret += UCAC4_DOUBLE_STAR_FLAG_STRINGS[self.double_star_flag]
|
|
229
|
+
ret += UCAC4Star.UCAC4_DOUBLE_STAR_FLAG_STRINGS[self.double_star_flag]
|
|
131
230
|
|
|
132
231
|
ret += ' TYPE='
|
|
133
232
|
if self.double_star_type is None:
|
|
134
233
|
ret += 'None'
|
|
135
234
|
else:
|
|
136
|
-
ret += UCAC4_DOUBLE_STAR_TYPE_STRINGS[self.double_star_type]
|
|
235
|
+
ret += UCAC4Star.UCAC4_DOUBLE_STAR_TYPE_STRINGS[self.double_star_type]
|
|
137
236
|
|
|
138
237
|
ret += ' | GALAXY '
|
|
139
238
|
if self.galaxy_match is None:
|
|
@@ -156,35 +255,34 @@ class UCAC4Star(Star):
|
|
|
156
255
|
if self.apass_mag_b is None:
|
|
157
256
|
ret += 'B None '
|
|
158
257
|
else:
|
|
159
|
-
ret += 'B
|
|
160
|
-
|
|
258
|
+
ret += f'B {self.apass_mag_b:6.3f} +/- {self.apass_mag_b_sigma:6.3f} '
|
|
259
|
+
|
|
161
260
|
if self.apass_mag_v is None:
|
|
162
261
|
ret += 'V None '
|
|
163
262
|
else:
|
|
164
|
-
ret += 'V
|
|
165
|
-
|
|
263
|
+
ret += f'V {self.apass_mag_v:6.3f} +/- {self.apass_mag_v_sigma:6.3f} '
|
|
264
|
+
|
|
166
265
|
if self.apass_mag_g is None:
|
|
167
266
|
ret += 'G None '
|
|
168
267
|
else:
|
|
169
|
-
ret += 'G
|
|
170
|
-
|
|
268
|
+
ret += f'G {self.apass_mag_g:6.3f} +/- {self.apass_mag_g_sigma:6.3f} '
|
|
269
|
+
|
|
171
270
|
if self.apass_mag_r is None:
|
|
172
271
|
ret += 'R None '
|
|
173
272
|
else:
|
|
174
|
-
ret += 'R
|
|
175
|
-
|
|
273
|
+
ret += f'R {self.apass_mag_r:6.3f} +/- {self.apass_mag_r_sigma:6.3f} '
|
|
274
|
+
|
|
176
275
|
if self.apass_mag_i is None:
|
|
177
276
|
ret += 'I None'
|
|
178
277
|
else:
|
|
179
|
-
ret += 'I
|
|
180
|
-
|
|
278
|
+
ret += f'I {self.apass_mag_i:6.3f} +/- {self.apass_mag_i_sigma:6.3f}'
|
|
279
|
+
|
|
181
280
|
ret += '\n'
|
|
182
281
|
|
|
183
282
|
if self.johnson_mag_b is None or self.johnson_mag_v is None:
|
|
184
283
|
ret += 'JOHNSON B None V None'
|
|
185
284
|
else:
|
|
186
|
-
ret += 'JOHNSON B
|
|
187
|
-
self.johnson_mag_v)
|
|
285
|
+
ret += f'JOHNSON B {self.johnson_mag_b:6.3f} V {self.johnson_mag_v:6.3f}'
|
|
188
286
|
ret += '\n'
|
|
189
287
|
|
|
190
288
|
return ret
|
|
@@ -270,62 +368,99 @@ UCAC4_FMT_RA = '=i'
|
|
|
270
368
|
UCAC4_RECORD_SIZE_RA = 4
|
|
271
369
|
assert struct.calcsize(UCAC4_FMT_RA) == UCAC4_RECORD_SIZE_RA
|
|
272
370
|
|
|
371
|
+
|
|
273
372
|
class UCAC4StarCatalog(StarCatalog):
|
|
274
|
-
|
|
373
|
+
"""A UCAC4 star catalog.
|
|
374
|
+
|
|
375
|
+
This class adds the following options to `find_stars`::
|
|
376
|
+
|
|
377
|
+
require_clean (bool, default True): Return only "clean" stars. Skip stars
|
|
378
|
+
that are streaks or have high proper motion that is not matched
|
|
379
|
+
or discrepant.
|
|
380
|
+
allow_double (bool, default True): If True, include double stars.
|
|
381
|
+
allow_galaxy (bool, default False): If True, include galaxies.
|
|
382
|
+
require_pm (bool, default True): If True, only return stars with measured proper
|
|
383
|
+
motion.
|
|
384
|
+
return_everything (bool, default False): If True, override the above options to
|
|
385
|
+
return all stars and galaxies.
|
|
386
|
+
optimize_ra (bool, default True): Optimize searching of RA through zone files.
|
|
387
|
+
Only useful for internal development.
|
|
388
|
+
"""
|
|
389
|
+
|
|
390
|
+
def __init__(self,
|
|
391
|
+
dir: Optional[str | Path | FCPath] = None) -> None:
|
|
392
|
+
"""Create a UCAC4StarCatalog.
|
|
393
|
+
|
|
394
|
+
Parameters:
|
|
395
|
+
dir: The path to the star catalog directory (may be a URL). Within
|
|
396
|
+
this directory should be the directory ``u4b``.
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
super().__init__()
|
|
400
|
+
|
|
275
401
|
if dir is None:
|
|
276
|
-
self.
|
|
402
|
+
self._dirname = FCPath(os.environ['UCAC4_PATH'])
|
|
277
403
|
else:
|
|
278
|
-
self.
|
|
404
|
+
self._dirname = FCPath(dir)
|
|
279
405
|
self.debug_level = 0
|
|
280
406
|
|
|
281
|
-
def _find_stars(self,
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
starting RA
|
|
303
|
-
"""
|
|
304
|
-
|
|
305
|
-
start_znum = int(max(np.floor((dec_min*DPR+90)*5)+1, 1))
|
|
306
|
-
end_znum = int(min(np.floor((dec_max*DPR+90-1e-15)*5)+1, 900))
|
|
407
|
+
def _find_stars(self,
|
|
408
|
+
ra_min: float,
|
|
409
|
+
ra_max: float,
|
|
410
|
+
dec_min: float,
|
|
411
|
+
dec_max: float,
|
|
412
|
+
vmag_min: Optional[float] = None,
|
|
413
|
+
vmag_max: Optional[float] = None,
|
|
414
|
+
full_result: bool = True,
|
|
415
|
+
**kwargs: Any) -> Iterator[UCAC4Star]:
|
|
416
|
+
|
|
417
|
+
# We do this here instead of as specific arguments because it works better
|
|
418
|
+
# with mypy
|
|
419
|
+
require_clean: bool = kwargs.pop('require_clean', True)
|
|
420
|
+
allow_double: bool = kwargs.pop('allow_double', True)
|
|
421
|
+
allow_galaxy: bool = kwargs.pop('allow_galaxy', False)
|
|
422
|
+
require_pm: bool = kwargs.pop('require_pm', True)
|
|
423
|
+
return_everything: bool = kwargs.pop('return_everything', False)
|
|
424
|
+
optimize_ra: bool = kwargs.pop('optimize_ra', True)
|
|
425
|
+
|
|
426
|
+
start_znum = int(max(np.floor((np.degrees(dec_min)+90)*5)+1, 1))
|
|
427
|
+
end_znum = int(min(np.floor((np.degrees(dec_max)+90-1e-15)*5)+1, 900))
|
|
307
428
|
|
|
308
429
|
for znum in range(start_znum, end_znum+1):
|
|
309
430
|
fn = self._zone_filename(znum)
|
|
310
|
-
with open(
|
|
431
|
+
with fn.open(mode='rb') as fp:
|
|
311
432
|
for star in self._find_stars_one_file(znum, fp,
|
|
312
433
|
ra_min, ra_max,
|
|
313
434
|
dec_min, dec_max,
|
|
314
|
-
|
|
435
|
+
vmag_min=vmag_min,
|
|
436
|
+
vmag_max=vmag_max,
|
|
437
|
+
require_clean=require_clean,
|
|
438
|
+
allow_double=allow_double,
|
|
439
|
+
allow_galaxy=allow_galaxy,
|
|
440
|
+
require_pm=require_pm,
|
|
441
|
+
return_everything=return_everything,
|
|
442
|
+
optimize_ra=optimize_ra,
|
|
443
|
+
full_result=full_result):
|
|
315
444
|
yield star
|
|
316
445
|
|
|
317
|
-
def _find_stars_one_file(self,
|
|
318
|
-
|
|
446
|
+
def _find_stars_one_file(self,
|
|
447
|
+
znum: int,
|
|
448
|
+
fp: Any,
|
|
449
|
+
ra_min: float,
|
|
450
|
+
ra_max: float,
|
|
451
|
+
dec_min: float,
|
|
452
|
+
dec_max: float,
|
|
453
|
+
vmag_min: Optional[float] = None,
|
|
454
|
+
vmag_max: Optional[float] = None,
|
|
455
|
+
require_clean: bool = True,
|
|
456
|
+
allow_double: bool = False,
|
|
457
|
+
allow_galaxy: bool = False,
|
|
458
|
+
require_pm: bool = True,
|
|
459
|
+
return_everything: bool = False,
|
|
460
|
+
optimize_ra: bool = True,
|
|
461
|
+
full_result: bool = True,
|
|
462
|
+
**kwargs: Any) -> Iterator[UCAC4Star]:
|
|
319
463
|
"""Yield the results for a single zone."""
|
|
320
|
-
full_result = kwargs.get('full_result', True)
|
|
321
|
-
vmag_min = kwargs.get('vmag_min', None)
|
|
322
|
-
vmag_max = kwargs.get('vmag_max', None)
|
|
323
|
-
require_clean = kwargs.get('require_clean', True)
|
|
324
|
-
allow_double = kwargs.get('allow_double', False)
|
|
325
|
-
allow_galaxy = kwargs.get('allow_galaxy', False)
|
|
326
|
-
require_pm = kwargs.get('require_pm', True)
|
|
327
|
-
return_everything = kwargs.get('return_everything', False)
|
|
328
|
-
optimize_ra = kwargs.get('optimize_ra', True)
|
|
329
464
|
|
|
330
465
|
if return_everything:
|
|
331
466
|
require_clean = False
|
|
@@ -334,7 +469,7 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
334
469
|
require_pm = False
|
|
335
470
|
|
|
336
471
|
if optimize_ra:
|
|
337
|
-
rec_num = self._find_starting_ra(fp, ra_min)
|
|
472
|
+
rec_num = self._find_starting_ra(fp, ra_min) # 0-based
|
|
338
473
|
else:
|
|
339
474
|
rec_num = 0
|
|
340
475
|
|
|
@@ -342,7 +477,7 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
342
477
|
record = fp.read(UCAC4_RECORD_SIZE)
|
|
343
478
|
if len(record) != UCAC4_RECORD_SIZE:
|
|
344
479
|
break
|
|
345
|
-
rec_num += 1
|
|
480
|
+
rec_num += 1 # This makes rec_num 1-based
|
|
346
481
|
parsed = struct.unpack(UCAC4_FMT, record)
|
|
347
482
|
star = UCAC4Star()
|
|
348
483
|
|
|
@@ -361,16 +496,15 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
361
496
|
# original UCAC observation cannot be recovered from these data.
|
|
362
497
|
# The declination is given in south pole distance (spd) and can be
|
|
363
498
|
# converted back to a true declination by subtracting 324000000 mas.
|
|
364
|
-
star.ra = parsed[0] * MAS_TO_RAD
|
|
365
|
-
star.dec = parsed[1] * MAS_TO_RAD - HALFPI
|
|
499
|
+
star.ra = cast(float, parsed[0] * MAS_TO_RAD)
|
|
500
|
+
star.dec = cast(float, parsed[1] * MAS_TO_RAD - HALFPI)
|
|
366
501
|
if star.ra >= ra_max:
|
|
367
502
|
# RA is in ascending order in the file
|
|
368
503
|
if self.debug_level > 1:
|
|
369
|
-
print('ID', parsed[42], 'SKIPPED RA AND REST OF FILE',
|
|
370
|
-
print(star.ra)
|
|
504
|
+
print('ID', parsed[42], 'SKIPPED RA AND REST OF FILE', star.ra)
|
|
371
505
|
break
|
|
372
506
|
if (star.ra < ra_min or
|
|
373
|
-
|
|
507
|
+
star.dec < dec_min or star.dec >= dec_max):
|
|
374
508
|
if self.debug_level > 1:
|
|
375
509
|
print('ID', parsed[42], 'SKIPPED RA/DEC', star.ra, star.dec)
|
|
376
510
|
continue
|
|
@@ -412,14 +546,12 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
412
546
|
if vmag_min is not None:
|
|
413
547
|
if star.vmag is None or star.vmag < vmag_min:
|
|
414
548
|
if self.debug_level > 1:
|
|
415
|
-
print('ID', parsed[42], 'SKIPPED MODEL MAG',
|
|
416
|
-
print(star.vmag_model)
|
|
549
|
+
print('ID', parsed[42], 'SKIPPED MODEL MAG', star.vmag_model)
|
|
417
550
|
continue
|
|
418
551
|
if vmag_max is not None:
|
|
419
552
|
if star.vmag is None or star.vmag > vmag_max:
|
|
420
553
|
if self.debug_level > 1:
|
|
421
|
-
print('ID', parsed[42], 'SKIPPED MODEL MAG',
|
|
422
|
-
print(star.vmag_model)
|
|
554
|
+
print('ID', parsed[42], 'SKIPPED MODEL MAG', star.vmag_model)
|
|
423
555
|
continue
|
|
424
556
|
|
|
425
557
|
###############
|
|
@@ -446,12 +578,12 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
446
578
|
# and 2 stars added from high proper motion surveys
|
|
447
579
|
# 8 = high proper motion solution in UCAC4, star not matched with PPMXL
|
|
448
580
|
# 9 = high proper motion solution in UCAC4, discrepant PM to PPMXL
|
|
449
|
-
# (see discussion of flags 8,9 in
|
|
581
|
+
# (see discussion of flags 8,9 in reduction section 2e above)
|
|
450
582
|
star.obj_type = parsed[5]
|
|
451
583
|
if (require_clean and
|
|
452
|
-
(star.obj_type
|
|
453
|
-
|
|
454
|
-
|
|
584
|
+
(star.obj_type in (UCAC4Star.UCAC4_OBJ_TYPE_STREAK,
|
|
585
|
+
UCAC4Star.UCAC4_OBJ_TYPE_HPM_NOT_MATCHED,
|
|
586
|
+
UCAC4Star.UCAC4_OBJ_TYPE_HPM_DISCREPANT))):
|
|
455
587
|
# Use with extreme caution
|
|
456
588
|
if self.debug_level:
|
|
457
589
|
print('ID', parsed[42], 'SKIPPED NOT CLEAN', star.obj_type)
|
|
@@ -516,14 +648,14 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
516
648
|
# (object size) information copied from the 2MASS extended source
|
|
517
649
|
# catalog.
|
|
518
650
|
star.galaxy_match = parsed[40]
|
|
519
|
-
star.extended_source = parsed[41]
|
|
651
|
+
star.extended_source = parsed[41] # XXX What units is this in?
|
|
520
652
|
if not allow_galaxy and (star.galaxy_match or star.extended_source):
|
|
521
653
|
if self.debug_level:
|
|
522
|
-
print('ID', parsed[42], 'SKIPPED GALAXY/EXTENDED',
|
|
523
|
-
|
|
654
|
+
print('ID', parsed[42], 'SKIPPED GALAXY/EXTENDED',
|
|
655
|
+
star.galaxy_match, star.extended_source)
|
|
524
656
|
continue
|
|
525
657
|
if star.galaxy_match:
|
|
526
|
-
star.galaxy_match = 10.**star.galaxy_match / 10. / 60.
|
|
658
|
+
star.galaxy_match = 10.**star.galaxy_match / 10. / 60. # Degrees
|
|
527
659
|
|
|
528
660
|
#################
|
|
529
661
|
# PROPER MOTION #
|
|
@@ -587,7 +719,8 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
587
719
|
if star.pm_rac_sigma is None:
|
|
588
720
|
star.pm_ra_sigma = None
|
|
589
721
|
else:
|
|
590
|
-
star.pm_ra_sigma = star.pm_rac_sigma /
|
|
722
|
+
star.pm_ra_sigma = (star.pm_rac_sigma /
|
|
723
|
+
np.cos(star.dec))
|
|
591
724
|
|
|
592
725
|
if pdse == 251:
|
|
593
726
|
star.pm_dec_sigma = 27.5 * MAS_TO_RAD
|
|
@@ -634,7 +767,7 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
634
767
|
# catalog like Hipparcos, Tycho or high proper motion data, a mean
|
|
635
768
|
# error in position and proper motion depending on the catalog and
|
|
636
769
|
# magnitude of the star was adopted.
|
|
637
|
-
star.rac_sigma = (parsed[7]+128.) * MAS_TO_RAD
|
|
770
|
+
star.rac_sigma = (parsed[7]+128.) * MAS_TO_RAD # RA * COS(DEC)
|
|
638
771
|
star.ra_sigma = star.rac_sigma / np.cos(star.dec)
|
|
639
772
|
star.dec_sigma = (parsed[8]+128.) * MAS_TO_RAD
|
|
640
773
|
|
|
@@ -817,8 +950,10 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
817
950
|
star.johnson_mag_b = star.apass_mag_b
|
|
818
951
|
star.johnson_mag_v = star.apass_mag_v
|
|
819
952
|
|
|
820
|
-
if (
|
|
821
|
-
|
|
953
|
+
if (star.apass_mag_b is not None and
|
|
954
|
+
parsed[33] == 0 and
|
|
955
|
+
star.apass_mag_v is not None and
|
|
956
|
+
parsed[34] == 0):
|
|
822
957
|
star.johnson_mag_v = (star.apass_mag_v -
|
|
823
958
|
0.09 * (star.apass_mag_b -
|
|
824
959
|
star.apass_mag_v))
|
|
@@ -837,7 +972,6 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
837
972
|
#37 60 (4) I*1 1/100 mag error of r magnitude from APASS (14)
|
|
838
973
|
#38 61 (5) I*1 1/100 mag error of i magnitude from APASS (14)
|
|
839
974
|
|
|
840
|
-
|
|
841
975
|
#######################
|
|
842
976
|
# CATALOG MATCH FLAGS #
|
|
843
977
|
#######################
|
|
@@ -935,26 +1069,25 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
935
1069
|
if parsed[43] == 0:
|
|
936
1070
|
star.id_str_ucac2 = None
|
|
937
1071
|
else:
|
|
938
|
-
star.id_str_ucac2 = 'UCAC2
|
|
939
|
-
parsed[44])
|
|
1072
|
+
star.id_str_ucac2 = f'UCAC2-{parsed[43]:03d}-{parsed[44]:06d}'
|
|
940
1073
|
|
|
941
1074
|
###############################
|
|
942
1075
|
# UCAC4 IDENTIFICATION NUMBER #
|
|
943
1076
|
###############################
|
|
944
1077
|
|
|
945
|
-
star.id_str = 'UCAC4
|
|
1078
|
+
star.id_str = f'UCAC4-{znum:03d}-{rec_num:06d}'
|
|
946
1079
|
|
|
947
1080
|
##################################################
|
|
948
1081
|
# COMPUTE SPECTRAL CLASS AND SURFACE TEMPERATURE #
|
|
949
1082
|
##################################################
|
|
950
1083
|
|
|
951
1084
|
if (star.johnson_mag_b is not None and
|
|
952
|
-
|
|
953
|
-
star.spectral_class =
|
|
1085
|
+
star.johnson_mag_v is not None):
|
|
1086
|
+
star.spectral_class = Star.sclass_from_bv(star.johnson_mag_b,
|
|
954
1087
|
star.johnson_mag_v)
|
|
955
1088
|
|
|
956
1089
|
if star.spectral_class is not None:
|
|
957
|
-
star.temperature =
|
|
1090
|
+
star.temperature = Star.temperature_from_sclass(star.
|
|
958
1091
|
spectral_class)
|
|
959
1092
|
|
|
960
1093
|
if self.debug_level:
|
|
@@ -964,13 +1097,16 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
964
1097
|
|
|
965
1098
|
#############################################################################
|
|
966
1099
|
|
|
967
|
-
def _zone_filename(self, znum):
|
|
1100
|
+
def _zone_filename(self, znum: int) -> FCPath:
|
|
968
1101
|
"""Convert a UCAC4 zone number to an absolute pathspec."""
|
|
969
|
-
fn = os.path.join(self.dirname, 'u4b', 'z%03d'%znum)
|
|
970
|
-
return fn
|
|
971
1102
|
|
|
972
|
-
|
|
1103
|
+
return self._dirname / 'u4b' / f'z{znum:03d}'
|
|
1104
|
+
|
|
1105
|
+
def _find_starting_ra(self,
|
|
1106
|
+
fp: Any,
|
|
1107
|
+
ra_min: float) -> int:
|
|
973
1108
|
"""Efficiently find the first record >= RA_MIN."""
|
|
1109
|
+
|
|
974
1110
|
if ra_min <= 0.:
|
|
975
1111
|
# No point in searching!
|
|
976
1112
|
return 0
|
|
@@ -995,81 +1131,8 @@ class UCAC4StarCatalog(StarCatalog):
|
|
|
995
1131
|
else:
|
|
996
1132
|
# Exact match!
|
|
997
1133
|
fp.seek(mid*UCAC4_RECORD_SIZE, os.SEEK_SET)
|
|
998
|
-
return mid // UCAC4_RECORD_SIZE
|
|
1134
|
+
return int(mid // UCAC4_RECORD_SIZE)
|
|
999
1135
|
|
|
1000
1136
|
# At this point lo is the best we can do
|
|
1001
1137
|
fp.seek(lo*UCAC4_RECORD_SIZE, os.SEEK_SET)
|
|
1002
|
-
return lo // UCAC4_RECORD_SIZE
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
#===============================================================================
|
|
1006
|
-
# UNIT TESTS
|
|
1007
|
-
#===============================================================================
|
|
1008
|
-
|
|
1009
|
-
import unittest
|
|
1010
|
-
|
|
1011
|
-
class Test_UCAC4StarCatalog(unittest.TestCase):
|
|
1012
|
-
|
|
1013
|
-
def runTest(self):
|
|
1014
|
-
cat = UCAC4StarCatalog('t:/external/ucac4')
|
|
1015
|
-
|
|
1016
|
-
# Zone 1
|
|
1017
|
-
num_pm = cat.count_stars(require_clean=False, allow_double=True,
|
|
1018
|
-
allow_galaxy=True, require_pm=True,
|
|
1019
|
-
dec_min=-90*RPD, dec_max=-89.8*RPD)
|
|
1020
|
-
num_all = cat.count_stars(require_clean=False, allow_double=True,
|
|
1021
|
-
allow_galaxy=True, require_pm=False,
|
|
1022
|
-
dec_min=-90*RPD, dec_max=-89.8*RPD)
|
|
1023
|
-
self.assertEqual(num_all, 206)
|
|
1024
|
-
self.assertEqual(num_all-num_pm, 5)
|
|
1025
|
-
|
|
1026
|
-
# Zone 451
|
|
1027
|
-
num_pm = cat.count_stars(require_clean=False, allow_double=True,
|
|
1028
|
-
allow_galaxy=True, require_pm=True,
|
|
1029
|
-
dec_min=0., dec_max=0.2*RPD)
|
|
1030
|
-
num_all = cat.count_stars(require_clean=False, allow_double=True,
|
|
1031
|
-
allow_galaxy=True, require_pm=False,
|
|
1032
|
-
dec_min=0., dec_max=0.2*RPD)
|
|
1033
|
-
self.assertEqual(num_all, 133410)
|
|
1034
|
-
self.assertEqual(num_all-num_pm, 6509) # zone_stats says 6394??
|
|
1035
|
-
|
|
1036
|
-
# Zone 900
|
|
1037
|
-
num_pm = cat.count_stars(require_clean=False, allow_double=True,
|
|
1038
|
-
allow_galaxy=True, require_pm=True,
|
|
1039
|
-
dec_min=89.8*RPD, dec_max=90.*RPD)
|
|
1040
|
-
num_all = cat.count_stars(require_clean=False, allow_double=True,
|
|
1041
|
-
allow_galaxy=True, require_pm=False,
|
|
1042
|
-
dec_min=89.8*RPD, dec_max=90.*RPD)
|
|
1043
|
-
self.assertEqual(num_all, 171)
|
|
1044
|
-
self.assertEqual(num_all-num_pm, 10) # zone_stats says 9??
|
|
1045
|
-
|
|
1046
|
-
# Compare slicing directions
|
|
1047
|
-
num_dec = 0
|
|
1048
|
-
for idec in range(20):
|
|
1049
|
-
num_dec += cat.count_stars(dec_min=0.2*idec*RPD,
|
|
1050
|
-
dec_max=0.2*(idec+1)*RPD,
|
|
1051
|
-
ra_min=60*RPD, ra_max=70*RPD)
|
|
1052
|
-
num_ra = 0
|
|
1053
|
-
for ira in range(10):
|
|
1054
|
-
num_ra += cat.count_stars(dec_min=0., dec_max=4.*RPD,
|
|
1055
|
-
ra_min=(ira+60)*RPD, ra_max=((ira+1)+60)*RPD)
|
|
1056
|
-
self.assertEqual(num_dec, num_ra)
|
|
1057
|
-
|
|
1058
|
-
# Compare optimized RA search with non-optimized
|
|
1059
|
-
for dec_idx in range(10):
|
|
1060
|
-
dec_min = (dec_idx*10-90.)*RPD
|
|
1061
|
-
dec_max = (dec_idx*10-89.8)*RPD
|
|
1062
|
-
for ra_min_idx in range(10):
|
|
1063
|
-
ra_min = ra_min_idx * 10 * RPD
|
|
1064
|
-
ra_max = ra_min + 10*RPD
|
|
1065
|
-
num_opt = cat.count_stars(dec_min=dec_min, dec_max=dec_max,
|
|
1066
|
-
ra_min=ra_min, ra_max=ra_max)
|
|
1067
|
-
num_no_opt = cat.count_stars(dec_min=dec_min, dec_max=dec_max,
|
|
1068
|
-
ra_min=ra_min, ra_max=ra_max,
|
|
1069
|
-
optimize_ra=False)
|
|
1070
|
-
self.assertEqual(num_opt, num_no_opt)
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
if __name__ == '__main__':
|
|
1075
|
-
unittest.main(verbosity=2)
|
|
1138
|
+
return int(lo // UCAC4_RECORD_SIZE)
|