rms-starcat 0.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.

starcat/ucac4.py ADDED
@@ -0,0 +1,1075 @@
1
+ ################################################################################
2
+ # starcat/ucac4.py
3
+ ################################################################################
4
+
5
+ # Zacharias, N. et al. 2013, The Astronomical Journal, 145, 44
6
+
7
+ from __future__ import print_function
8
+
9
+ try:
10
+ from starcatalog import *
11
+ except ImportError:
12
+ from .starcatalog import *
13
+ import numpy as np
14
+ import os.path
15
+ import struct
16
+
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
+
61
+ class UCAC4Star(Star):
62
+ """A holder for star attributes.
63
+
64
+ This class includes attributes unique to the UCAC4 catalog."""
65
+
66
+ def __init__(self):
67
+ # Initialize the standard fields
68
+ Star.__init__(self)
69
+
70
+ # Initialize the UCAC4-specific fields
71
+ self.vmag_model = None
72
+ self.obj_type = None
73
+ self.double_star_flag = None
74
+ self.double_star_type = None
75
+ self.galaxy_match = None
76
+ self.extended_source = None
77
+ self.pm_rac = None
78
+ self.pm_rac_sigma = None
79
+ self.rac_sigma = None
80
+ self.num_img_total = None
81
+ self.num_img_used = None
82
+ self.num_cat_pm = None
83
+ self.ra_mean_epoch = None
84
+ self.dec_mean_epoch = None
85
+ self.cat_match = None
86
+ self.apass_mag_b = None
87
+ self.apass_mag_v = None
88
+ self.apass_mag_g = None
89
+ self.apass_mag_r = None
90
+ self.apass_mag_i = None
91
+ self.apass_mag_b_sigma = None
92
+ self.apass_mag_v_sigma = None
93
+ self.apass_mag_g_sigma = None
94
+ self.apass_mag_r_sigma = None
95
+ self.apass_mag_i_sigma = None
96
+ self.johnson_mag_b = None
97
+ self.johnson_mag_v = None
98
+ self.id_str = None
99
+ self.id_str_ucac2 = None
100
+ self.spectral_class = None
101
+ self.temperature = None
102
+
103
+ def __str__(self):
104
+ ret = Star.__str__(self)
105
+
106
+ ret += 'OBJTYPE '
107
+ if self.obj_type is None:
108
+ ret += 'None'
109
+ else:
110
+ ret += UCAC4_OBJ_TYPE_STRINGS[self.obj_type]
111
+ ret += ' | '
112
+
113
+ if self.vmag_model is None:
114
+ ret += 'APER VMAG None'
115
+ else:
116
+ ret += 'APER VMAG %6.3f' % self.vmag_model
117
+ ret += ' | '
118
+
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
+ ret += '\n'
125
+
126
+ ret += 'DBL STAR FLAG='
127
+ if self.double_star_flag is None:
128
+ ret += 'None'
129
+ else:
130
+ ret += UCAC4_DOUBLE_STAR_FLAG_STRINGS[self.double_star_flag]
131
+
132
+ ret += ' TYPE='
133
+ if self.double_star_type is None:
134
+ ret += 'None'
135
+ else:
136
+ ret += UCAC4_DOUBLE_STAR_TYPE_STRINGS[self.double_star_type]
137
+
138
+ ret += ' | GALAXY '
139
+ if self.galaxy_match is None:
140
+ ret += 'NONE'
141
+ elif self.galaxy_match:
142
+ ret += 'Yes'
143
+ else:
144
+ ret += 'No'
145
+
146
+ ret += ' | EXT SOURCE '
147
+ if self.extended_source is None:
148
+ ret += 'NONE'
149
+ elif self.extended_source:
150
+ ret += 'Yes'
151
+ else:
152
+ ret += 'No'
153
+ ret += '\n'
154
+
155
+ ret += 'APASS '
156
+ if self.apass_mag_b is None:
157
+ ret += 'B None '
158
+ else:
159
+ ret += 'B %6.3f +/- %6.3f ' % (self.apass_mag_b,
160
+ self.apass_mag_b_sigma)
161
+ if self.apass_mag_v is None:
162
+ ret += 'V None '
163
+ else:
164
+ ret += 'V %6.3f +/- %6.3f ' % (self.apass_mag_v,
165
+ self.apass_mag_v_sigma)
166
+ if self.apass_mag_g is None:
167
+ ret += 'G None '
168
+ else:
169
+ ret += 'G %6.3f +/- %6.3f ' % (self.apass_mag_g,
170
+ self.apass_mag_g_sigma)
171
+ if self.apass_mag_r is None:
172
+ ret += 'R None '
173
+ else:
174
+ ret += 'R %6.3f +/- %6.3f ' % (self.apass_mag_r,
175
+ self.apass_mag_r_sigma)
176
+ if self.apass_mag_i is None:
177
+ ret += 'I None'
178
+ else:
179
+ ret += 'I %6.3f +/- %6.3f' % (self.apass_mag_i,
180
+ self.apass_mag_i_sigma)
181
+ ret += '\n'
182
+
183
+ if self.johnson_mag_b is None or self.johnson_mag_v is None:
184
+ ret += 'JOHNSON B None V None'
185
+ else:
186
+ ret += 'JOHNSON B %6.3f V %6.3f' % (self.johnson_mag_b,
187
+ self.johnson_mag_v)
188
+ ret += '\n'
189
+
190
+ return ret
191
+
192
+ # TODO
193
+ # self.cat_match = None
194
+ # self.num_img_total = None
195
+ # self.num_img_used = None
196
+ # self.num_cat_pm = None
197
+ # self.ra_mean_epoch = None
198
+ # self.dec_mean_epoch = None
199
+ # self.id_str = None
200
+ # self.id_str_ucac2 = None
201
+
202
+
203
+ #col byte item fmt unit explanation notes
204
+ #---------------------------------------------------------------------------
205
+ # 1 1- 4 ra I*4 mas right ascension at epoch J2000.0 (ICRS) (1)
206
+ # 2 5- 8 spd I*4 mas south pole distance epoch J2000.0 (ICRS) (1)
207
+ # 3 9-10 magm I*2 millimag UCAC fit model magnitude (2)
208
+ # 4 11-12 maga I*2 millimag UCAC aperture magnitude (2)
209
+ # 5 13 sigmag I*1 1/100 mag error of UCAC magnitude (3)
210
+ # 6 14 objt I*1 object type (4)
211
+ # 7 15 cdf I*1 combined double star flag (5)
212
+ # 15 bytes
213
+ # 8 16 sigra I*1 mas s.e. at central epoch in RA (*cos Dec) (6)
214
+ # 9 17 sigdc I*1 mas s.e. at central epoch in Dec (6)
215
+ #10 18 na1 I*1 total # of CCD images of this star
216
+ #11 19 nu1 I*1 # of CCD images used for this star (7)
217
+ #12 20 cu1 I*1 # catalogs (epochs) used for proper motions
218
+ # 5 bytes
219
+ #13 21-22 cepra I*2 0.01 yr central epoch for mean RA, minus 1900
220
+ #14 23-24 cepdc I*2 0.01 yr central epoch for mean Dec,minus 1900
221
+ #15 25-26 pmrac I*2 0.1 mas/yr proper motion in RA*cos(Dec) (8)
222
+ #16 27-28 pmdc I*2 0.1 mas/yr proper motion in Dec
223
+ #17 29 sigpmr I*1 0.1 mas/yr s.e. of pmRA * cos Dec (9)
224
+ #18 30 sigpmd I*1 0.1 mas/yr s.e. of pmDec (9)
225
+ # 10 bytes
226
+ #19 31-34 pts_key I*4 2MASS unique star identifier (10)
227
+ #20 35-36 j_m I*2 millimag 2MASS J magnitude
228
+ #21 37-38 h_m I*2 millimag 2MASS H magnitude
229
+ #22 39-40 k_m I*2 millimag 2MASS K_s magnitude
230
+ #23 41 icqflg I*1 2MASS cc_flg*10 + ph_qual flag for J (11)
231
+ #24 42 (2) I*1 2MASS cc_flg*10 + ph_qual flag for H (11)
232
+ #25 43 (3) I*1 2MASS cc_flg*10 + ph_qual flag for K_s (11)
233
+ #26 44 e2mpho I*1 1/100 mag error 2MASS J magnitude (12)
234
+ #27 45 (2) I*1 1/100 mag error 2MASS H magnitude (12)
235
+ #28 46 (3) I*1 1/100 mag error 2MASS K_s magnitude (12)
236
+ # 16 bytes
237
+ #29 47-48 apasm I*2 millimag B magnitude from APASS (13)
238
+ #30 49-50 (2) I*2 millimag V magnitude from APASS (13)
239
+ #31 51-52 (3) I*2 millimag g magnitude from APASS (13)
240
+ #32 53-54 (4) I*2 millimag r magnitude from APASS (13)
241
+ #33 55-56 (5) I*2 millimag i magnitude from APASS (13)
242
+ #34 57 apase I*1 1/100 mag error of B magnitude from APASS (14)
243
+ #35 58 (2) I*1 1/100 mag error of V magnitude from APASS (14)
244
+ #36 59 (3) I*1 1/100 mag error of g magnitude from APASS (14)
245
+ #37 60 (4) I*1 1/100 mag error of r magnitude from APASS (14)
246
+ #38 61 (5) I*1 1/100 mag error of i magnitude from APASS (14)
247
+ #39 62 gcflg I*1 Yale SPM g-flag*10 c-flag (15)
248
+ # 16 bytes
249
+ #40 63-66 icf(1) I*4 FK6-Hipparcos-Tycho source flag (16)
250
+ #41 icf(2) .. AC2000 catalog match flag (17)
251
+ #42 icf(3) .. AGK2 Bonn catalog match flag (17)
252
+ #43 icf(4) .. AKG2 Hamburg catalog match flag (17)
253
+ #44 icf(5) .. Zone Astrog. catalog match flag (17)
254
+ #45 icf(6) .. Black Birch catalog match flag (17)
255
+ #46 icf(7) .. Lick Astrog. catalog match flag (17)
256
+ #47 icf(8) .. NPM Lick catalog match flag (17)
257
+ #48 icf(9) .. SPM YSJ1 catalog match flag (17)
258
+ # 4 bytes
259
+ #49 67 leda I*1 LEDA galaxy match flag (18)
260
+ #50 68 x2m I*1 2MASS extend.source flag (19)
261
+ #51 69-72 rnm I*4 unique star identification number (20)
262
+ #52 73-74 zn2 I*2 zone number of UCAC2 (0 = no match) (21)
263
+ #53 75-78 rn2 I*4 running record number along UCAC2 zone (21)
264
+
265
+ UCAC4_FMT = '=iihhbbbbbbbbhhhhbbihhhbbbbbbhhhhhbbbbbbibbihi'
266
+ UCAC4_RECORD_SIZE = 78
267
+ assert struct.calcsize(UCAC4_FMT) == UCAC4_RECORD_SIZE
268
+
269
+ UCAC4_FMT_RA = '=i'
270
+ UCAC4_RECORD_SIZE_RA = 4
271
+ assert struct.calcsize(UCAC4_FMT_RA) == UCAC4_RECORD_SIZE_RA
272
+
273
+ class UCAC4StarCatalog(StarCatalog):
274
+ def __init__(self, dir=None):
275
+ if dir is None:
276
+ self.dirname = os.environ["UCAC4_DIR"]
277
+ else:
278
+ self.dirname = dir
279
+ self.debug_level = 0
280
+
281
+ def _find_stars(self, ra_min, ra_max, dec_min, dec_max, **kwargs):
282
+ """Yield the results for all zones in the DEC range.
283
+
284
+ Optional arguments: DEFAULT
285
+ ra_min, ra_max 0, 2PI RA range in radians
286
+ dec_min, dec_max -PI, PI DEC range in radians
287
+ vmag_min, vmag_max ALL Magnitude range
288
+ require_clean True Only return stars that are clean
289
+ detections
290
+ allow_double False Allow double stars
291
+ allow_galaxy False Allow galaxies and extended objects
292
+ require_pm True Only return stars with known proper
293
+ motion
294
+ return_everything False Override require_clean,
295
+ allow_double, allow_galaxy, and
296
+ require_pm so that every entry
297
+ is returned.
298
+ full_result True Populate all fields
299
+ False: Stop after fields required
300
+ for matching criteria
301
+ optimize_ra True Use a binary search to find the
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))
307
+
308
+ for znum in range(start_znum, end_znum+1):
309
+ fn = self._zone_filename(znum)
310
+ with open(fn, 'rb') as fp:
311
+ for star in self._find_stars_one_file(znum, fp,
312
+ ra_min, ra_max,
313
+ dec_min, dec_max,
314
+ **kwargs):
315
+ yield star
316
+
317
+ def _find_stars_one_file(self, znum, fp, ra_min, ra_max, dec_min, dec_max,
318
+ **kwargs):
319
+ """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
+
330
+ if return_everything:
331
+ require_clean = False
332
+ allow_double = True
333
+ allow_galaxy = True
334
+ require_pm = False
335
+
336
+ if optimize_ra:
337
+ rec_num = self._find_starting_ra(fp, ra_min) # 0-based
338
+ else:
339
+ rec_num = 0
340
+
341
+ while True:
342
+ record = fp.read(UCAC4_RECORD_SIZE)
343
+ if len(record) != UCAC4_RECORD_SIZE:
344
+ break
345
+ rec_num += 1 # This makes rec_num 1-based
346
+ parsed = struct.unpack(UCAC4_FMT, record)
347
+ star = UCAC4Star()
348
+
349
+ ###########
350
+ # RA, DEC #
351
+ ###########
352
+
353
+ # 1 1- 4 ra I*4 mas right ascension at epoch J2000.0 (ICRS) (1)
354
+ # 2 5- 8 spd I*4 mas south pole distance epoch J2000.0 (ICRS) (1)
355
+ # Note (1): Positions are on the International Celestial Reference
356
+ # System (ICRS) as represented by the Hipparcos / Tycho-2 catalogs.
357
+ # The epoch for the positions of all stars is J2000.0; the weighted
358
+ # mean catalog position was updated using the provided proper
359
+ # motions. The observational UCAC position is but one of several
360
+ # going into these values and is not given in the UCAC4; thus the
361
+ # original UCAC observation cannot be recovered from these data.
362
+ # The declination is given in south pole distance (spd) and can be
363
+ # 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
366
+ if star.ra >= ra_max:
367
+ # RA is in ascending order in the file
368
+ if self.debug_level > 1:
369
+ print('ID', parsed[42], 'SKIPPED RA AND REST OF FILE', end=' ')
370
+ print(star.ra)
371
+ break
372
+ if (star.ra < ra_min or
373
+ star.dec < dec_min or star.dec >= dec_max):
374
+ if self.debug_level > 1:
375
+ print('ID', parsed[42], 'SKIPPED RA/DEC', star.ra, star.dec)
376
+ continue
377
+
378
+ #############
379
+ # MAGNITUDE #
380
+ #############
381
+
382
+ # 3 9-10 magm I*2 millimag UCAC fit model magnitude (2)
383
+ # 4 11-12 maga I*2 millimag UCAC aperture magnitude (2)
384
+ # 5 13 sigmag I*1 1/100 mag error of UCAC magnitude (3)
385
+ # Note (2): Unknown, or unrealistic photometric results are set to
386
+ # magnitude = 20 (20000 mmag entry in catalog). Systematic errors
387
+ # are expected to be below 0.1 mag for magm,maga photometric results
388
+ # obtained from the UCAC CCD pixel data. The aperture photometry
389
+ # is considered more robust, particularly for "odd" cases, while
390
+ # the model fit magnitude is expected to be more accurate for
391
+ # "well behaved" stars.
392
+ #
393
+ # Note (3): A value of 99 for error in magnitude means "no data".
394
+ # For many stars a photometric error based on the scatter from
395
+ # individual observations of that star on different CCD frames
396
+ # could be obtained. A model error was also attempted to be
397
+ # assigned, based on the S/N ratio. The error quoted here is
398
+ # the larger of the 2. If that error exceeds 0.9 mag the error
399
+ # was set to 0.9 mag (= value 90 in catalog data, unit = 10 mmag).
400
+ if parsed[2] == 20000:
401
+ star.vmag_model = None
402
+ else:
403
+ star.vmag_model = parsed[2] / 1000.
404
+ if parsed[3] == 20000:
405
+ star.vmag = None
406
+ else:
407
+ star.vmag = parsed[3] / 1000.
408
+ if parsed[4] == 99:
409
+ star.vmag_sigma = None
410
+ else:
411
+ star.vmag_sigma = parsed[4] / 100.
412
+ if vmag_min is not None:
413
+ if star.vmag is None or star.vmag < vmag_min:
414
+ if self.debug_level > 1:
415
+ print('ID', parsed[42], 'SKIPPED MODEL MAG', end=' ')
416
+ print(star.vmag_model)
417
+ continue
418
+ if vmag_max is not None:
419
+ if star.vmag is None or star.vmag > vmag_max:
420
+ if self.debug_level > 1:
421
+ print('ID', parsed[42], 'SKIPPED MODEL MAG', end=' ')
422
+ print(star.vmag_model)
423
+ continue
424
+
425
+ ###############
426
+ # OBJECT TYPE #
427
+ ###############
428
+
429
+ # 6 14 objt I*1 object type (4)
430
+ # Note (4): The object type flag is used to identify possible problems
431
+ # with a star or the source of data. Of the individual image flags
432
+ # the one with the largest value (worst problem case) is propagated
433
+ # into this object type flag, unless it is superseded by an overriding
434
+ # flag at the combined image stage.
435
+ # The object type flag has the following meaning:
436
+ #
437
+ # 0 = good, clean star (from MPOS), no known problem
438
+ # 1 = largest flag of any image = near overexposed star (from MPOS)
439
+ # 2 = largest flag of any image = possible streak object (from MPOS)
440
+ # 3 = high proper motion (HPM) star, match with external PM file (MPOS)
441
+ # 4 = actually use external HPM data instead of UCAC4 observ.data
442
+ # (accuracy of positions varies between catalogs)
443
+ # 5 = poor proper motion solution, report only CCD epoch position
444
+ # 6 = substitute poor astrometric results by FK6/Hip/Tycho-2 data
445
+ # 7 = added supplement star (no CCD data) from FK6/Hip/Tycho-2 data,
446
+ # and 2 stars added from high proper motion surveys
447
+ # 8 = high proper motion solution in UCAC4, star not matched with PPMXL
448
+ # 9 = high proper motion solution in UCAC4, discrepant PM to PPMXL
449
+ # (see discussion of flags 8,9 in redcution section 2e above)
450
+ star.obj_type = parsed[5]
451
+ if (require_clean and
452
+ (star.obj_type == UCAC4_OBJ_TYPE_STREAK or
453
+ star.obj_type == UCAC4_OBJ_TYPE_HPM_NOT_MATCHED or
454
+ star.obj_type == UCAC4_OBJ_TYPE_HPM_DISCREPANT)):
455
+ # Use with extreme caution
456
+ if self.debug_level:
457
+ print('ID', parsed[42], 'SKIPPED NOT CLEAN', star.obj_type)
458
+ continue
459
+
460
+ #############################
461
+ # COMBINED DOUBLE STAR FLAG #
462
+ #############################
463
+
464
+ # 7 15 cdf I*1 combined double star flag (5)
465
+ # Note (5): The cdf flag is a combined double star flag used to indicate
466
+ # the type/quality of double star fit. It is a combination of 2 flags,
467
+ # cdf = 10 * dsf + dst with the following meaning:
468
+ #
469
+ # dsf = double star flag = overall classification
470
+ # 0 = single star
471
+ # 1 = component #1 of "good" double star
472
+ # 2 = component #2 of "good" double star
473
+ # 3 = blended image
474
+ #
475
+ # dst = double star type, from pixel data image profile fits,
476
+ # largest value of all images used for this star
477
+ # 0 = no double star, not sufficient #pixels or elongation
478
+ # to even call double star fit subroutine
479
+ # 1 = elongated image but no more than 1 peak detected
480
+ # 2 = 2 separate peaks detected -> try double star fit
481
+ # 3 = secondary peak found on each side of primary
482
+ # 4 = case 1 after successful double fit (small separ. blended image)
483
+ # 5 = case 2 after successful double fit (most likely real double)
484
+ # 6 = case 3 after successful double fit (brighter secondary picked)
485
+ #
486
+ # A word of caution: often a dsf= 1 or 2 image is paired with a dsf= 3.
487
+ # If for a star any of the several images reveals a "blended image",
488
+ # that higher dsf=3 flag is carried into the output file. This can
489
+ # happen for a regular double star with unique components 1 and 2.
490
+ # A flag dsf=3 means this could be component 1 or 2 but at least on
491
+ # one CCD frame a blended image was detected. This blend could be
492
+ # with the other component, or a spurious image or artifact.
493
+ # The double star flags need to be interpreted with caution; anything
494
+ # but a zero means "likely some double star component or blended image".
495
+ cdf = parsed[6]
496
+ if not allow_double and cdf != 0:
497
+ if self.debug_level:
498
+ print('ID', parsed[42], 'SKIPPED DOUBLE', cdf)
499
+ continue
500
+ star.double_star_flag = cdf // 10
501
+ star.double_star_type = cdf % 10
502
+
503
+ #################################
504
+ # GALAXIES AND EXTENDED SOURCES #
505
+ #################################
506
+
507
+ #(41)49 67 leda I*1 LEDA galaxy match flag (18)
508
+ #(42)50 68 x2m I*1 2MASS extend.source flag (19)
509
+ # Note (18): This flag is either 0 (no match) or contains the log10 of
510
+ # the apparent total diameter for I-band (object size) information
511
+ # (unit = 0.1 arcmin) copied from the LEDA catalog (galaxies).
512
+ # A size value of less than 1 has been rounded up to 1.
513
+ #
514
+ # Note (19): This flag is either 0 (no match) or contains the length of
515
+ # the semi-major axis of the fiducial ellipse at the K-band
516
+ # (object size) information copied from the 2MASS extended source
517
+ # catalog.
518
+ star.galaxy_match = parsed[40]
519
+ star.extended_source = parsed[41] # XXX What units is this in?
520
+ if not allow_galaxy and (star.galaxy_match or star.extended_source):
521
+ if self.debug_level:
522
+ print('ID', parsed[42], 'SKIPPED GALAXY/EXTENDED', end=' ')
523
+ print(star.galaxy_match, star.extended_source)
524
+ continue
525
+ if star.galaxy_match:
526
+ star.galaxy_match = 10.**star.galaxy_match / 10. / 60. # Degrees
527
+
528
+ #################
529
+ # PROPER MOTION #
530
+ #################
531
+
532
+ #15 25-26 pmrac I*2 0.1 mas/yr proper motion in RA*cos(Dec) (8)
533
+ #16 27-28 pmdc I*2 0.1 mas/yr proper motion in Dec
534
+ #17 29 sigpmr I*1 0.1 mas/yr s.e. of pmRA * cos Dec (9)
535
+ #18 30 sigpmd I*1 0.1 mas/yr s.e. of pmDec (9)
536
+ # Note (8): A value of 32767 for either proper motion component means
537
+ # the real PM of that star is larger and found in the extra table
538
+ # file u4hpm.dat (32 stars, ASCII). The cross reference is established
539
+ # by the unique, modified MPOS number (column 51 of main data file),
540
+ # which is also given on the HPM supplement stars file.
541
+ # For stars without valid proper motion the proper motion data are set
542
+ # to 0. However, valid proper motions can also be 0. The "no data"
543
+ # case is indicated by the sigma proper motion columns (see below).
544
+ #
545
+ # Note (9): Values in the binary data files are represented as signed,
546
+ # 1-byte integer (range -128 to 127). Add 128 to bring those values
547
+ # to the range of 0 to 255, which is the error in proper motion in
548
+ # unit of 0.1 mas/yr, with the following exception.
549
+ # Data entries above 250 indicate larger errors as follows:
550
+ # 251 --> 275 = 27.5 mas/yr
551
+ # 252 --> 325 = 32.5 mas/yr
552
+ # 253 --> 375 = 37.5 mas/yr
553
+ # 254 --> 450 = 45.0 mas/yr
554
+ # 255 --> "no data" = set to 500 for output tables
555
+ #
556
+ # For astrometric data copied from the FK6, Hipparcos and Tycho-2
557
+ # catalogs a mean error in positions was adopted depending on input
558
+ # catalog and the brightness of the star rather than giving the
559
+ # individual star's error quoted in those catalogs.
560
+ star.pm_rac = parsed[14] * 0.1 * MAS_TO_RAD * YEAR_TO_SEC
561
+ star.pm_ra = star.pm_rac / np.cos(star.dec)
562
+ star.pm_dec = parsed[15] * 0.1 * MAS_TO_RAD * YEAR_TO_SEC
563
+
564
+ if parsed[14] == 32767 or parsed[15] == 32767:
565
+ # PM is too large and needs to be looked up in another
566
+ # table, which we don't support yet. XXX
567
+ star.pm_rac = None
568
+ star.pm_ra = None
569
+ star.pm_dec = None
570
+
571
+ prse = parsed[16]+128
572
+ pdse = parsed[17]+128
573
+ star.pm_rac_sigma = prse * 0.1 * MAS_TO_RAD * YEAR_TO_SEC
574
+ star.pm_dec_sigma = pdse * 0.1 * MAS_TO_RAD * YEAR_TO_SEC
575
+ if prse == 251:
576
+ star.pm_rac_sigma = 27.5 * MAS_TO_RAD * YEAR_TO_SEC
577
+ elif prse == 252:
578
+ star.pm_rac_sigma = 32.5 * MAS_TO_RAD * YEAR_TO_SEC
579
+ elif prse == 253:
580
+ star.pm_rac_sigma = 37.5 * MAS_TO_RAD * YEAR_TO_SEC
581
+ elif prse == 254:
582
+ star.pm_rac_sigma = 45.0 * MAS_TO_RAD * YEAR_TO_SEC
583
+ elif prse == 255:
584
+ star.pm_rac_sigma = None
585
+ if star.pm_rac == 0:
586
+ star.pm_rac = None
587
+ if star.pm_rac_sigma is None:
588
+ star.pm_ra_sigma = None
589
+ else:
590
+ star.pm_ra_sigma = star.pm_rac_sigma / np.cos(star.dec)
591
+
592
+ if pdse == 251:
593
+ star.pm_dec_sigma = 27.5 * MAS_TO_RAD
594
+ elif pdse == 252:
595
+ star.pm_dec_sigma = 32.5 * MAS_TO_RAD
596
+ elif pdse == 253:
597
+ star.pm_dec_sigma = 37.5 * MAS_TO_RAD
598
+ elif pdse == 254:
599
+ star.pm_dec_sigma = 45.0 * MAS_TO_RAD
600
+ elif pdse == 255:
601
+ star.pm_dec_sigma = None
602
+ if star.pm_dec == 0:
603
+ star.pm_dec = None
604
+
605
+ if require_pm and (star.pm_ra is None or star.pm_dec is None):
606
+ if self.debug_level:
607
+ print('ID', parsed[42], 'SKIPPED NO PM', parsed[14:18])
608
+ continue
609
+
610
+ #################################
611
+ #################################
612
+ ### END OF SELECTION CRITERIA ###
613
+ #################################
614
+ #################################
615
+
616
+ if not full_result:
617
+ if self.debug_level:
618
+ print('ID', parsed[42], 'OK!')
619
+ yield star
620
+ continue
621
+
622
+ ###########################
623
+ # RA/DEC SYSTEMATIC ERROR #
624
+ ###########################
625
+
626
+ # 8 16 sigra I*1 mas s.e. at central epoch in RA (*cos Dec) (6)
627
+ # 9 17 sigdc I*1 mas s.e. at central epoch in Dec (6)
628
+ # Note (6): The range of values here is 1 to 255 which is represented
629
+ # as a signed 1-byte integer (range -127 to 127); thus add 128 to the
630
+ # integer number found in the data file. There is no 0 mas value;
631
+ # data less than 1 mas have been set to 1 mas. Original data larger
632
+ # than 255 mas have been set to 255.
633
+ # If the astrometric data for a star was substituted from an external
634
+ # catalog like Hipparcos, Tycho or high proper motion data, a mean
635
+ # error in position and proper motion depending on the catalog and
636
+ # magnitude of the star was adopted.
637
+ star.rac_sigma = (parsed[7]+128.) * MAS_TO_RAD # RA * COS(DEC)
638
+ star.ra_sigma = star.rac_sigma / np.cos(star.dec)
639
+ star.dec_sigma = (parsed[8]+128.) * MAS_TO_RAD
640
+
641
+ ##############
642
+ # IMAGE INFO #
643
+ ##############
644
+
645
+ #10 18 na1 I*1 total # of CCD images of this star
646
+ #11 19 nu1 I*1 # of CCD images used for this star (7)
647
+ #12 20 cu1 I*1 # catalogs (epochs) used for proper motions
648
+ # Note (7): A zero for the number of used images indicates that all images
649
+ # have some "problem" (such as overexposure). In that case an unweighted
650
+ # mean over all available images (na) is taken to derive the mean
651
+ # position, while normally a weighted mean was calculated based on
652
+ # the "good" images, excluding possible problem images (nu <= na).
653
+ star.num_img_total = parsed[9]
654
+ star.num_img_used = parsed[10]
655
+ star.num_cat_pm = parsed[11]
656
+
657
+ #########
658
+ # EPOCH #
659
+ #########
660
+
661
+ #13 21-22 cepra I*2 0.01 yr central epoch for mean RA, minus 1900
662
+ #14 23-24 cepdc I*2 0.01 yr central epoch for mean Dec,minus 1900
663
+ star.ra_mean_epoch = parsed[12] * 0.01 + 1900
664
+ star.dec_mean_epoch = parsed[13] * 0.01 + 1900
665
+
666
+ ##############
667
+ # 2MASS DATA #
668
+ ##############
669
+
670
+ #19 31-34 pts_key I*4 2MASS unique star identifier (10)
671
+ #20 35-36 j_m I*2 millimag 2MASS J magnitude
672
+ #21 37-38 h_m I*2 millimag 2MASS H magnitude
673
+ #22 39-40 k_m I*2 millimag 2MASS K_s magnitude
674
+ #23 41 icqflg I*1 2MASS cc_flg*10 + ph_qual flag for J (11)
675
+ #24 42 (2) I*1 2MASS cc_flg*10 + ph_qual flag for H (11)
676
+ #25 43 (3) I*1 2MASS cc_flg*10 + ph_qual flag for K_s (11)
677
+ #26 44 e2mpho I*1 1/100 mag error 2MASS J magnitude (12)
678
+ #27 45 (2) I*1 1/100 mag error 2MASS H magnitude (12)
679
+ #28 46 (3) I*1 1/100 mag error 2MASS K_s magnitude (12)
680
+ # Note (10): The 2MASS items copied into UCAC4 are described at
681
+ # pegasus.astro.umass.edu/ipac_wget/releases/allsky/doc/sec2_2a.html
682
+ #
683
+ # Note (11): For each 2MASS bandpass a combined flag was created
684
+ # (cc_flg*10 + ph_qual) consisting of the contamination flag (0 to 5)
685
+ # and the photometric quality flag (0 to 8).
686
+ #
687
+ # 0 = cc_flg 2MASS 0, no artifacts or contamination
688
+ # 1 = cc_flg 2MASS p, source may be contaminated by a latent image
689
+ # 2 = cc_flg 2MASS c, photometric confusion
690
+ # 3 = cc_flg 2MASS d, diffraction spike confusion
691
+ # 4 = cc_flg 2MASS s, electronic stripe
692
+ # 5 = cc_flg 2MASS b, bandmerge confusion
693
+ #
694
+ # 0 = no ph_qual flag
695
+ # 1 = ph_qual 2MASS X, no valid brightness estimate
696
+ # 2 = ph_qual 2MASS U, upper limit on magnitude
697
+ # 3 = ph_qual 2MASS F, no reliable estimate of the photometric error
698
+ # 4 = ph_qual 2MASS E, goodness-of-fit quality of profile-fit poor
699
+ # 5 = ph_qual 2MASS A, valid measurement, [jhk]snr>10 AND [jhk]cmsig<0.10857
700
+ # 6 = ph_qual 2MASS B, valid measurement, [jhk]snr> 7 AND [jhk]cmsig<0.15510
701
+ # 7 = ph_qual 2MASS C, valid measurement, [jhk]snr> 5 AND [jhk]cmsig<0.21714
702
+ # 8 = ph_qual 2MASS D, valid measurement, no [jhk]snr OR [jhk]cmsig req.
703
+ #
704
+ # For example icqflg = 05 is decoded to be cc_flg=0, and ph_qual=5, meaning
705
+ # no artifacts or contamination from cc_flg and 2MASS qual flag = "A" .
706
+ #
707
+ # Note (12): The photometric errors from 2MASS were rounded by 1 digit
708
+ # here to fit into fewer bytes (1/100 mag instead of millimag).
709
+ # These data were taken from the j_msigcom, h_msigcom, and k_msigcom columns
710
+ # of the 2MASS point source catalog. See note (10).
711
+
712
+ ##############
713
+ # APASS DATA #
714
+ ##############
715
+
716
+ #29 47-48 apasm I*2 millimag B magnitude from APASS (13)
717
+ #30 49-50 (2) I*2 millimag V magnitude from APASS (13)
718
+ #31 51-52 (3) I*2 millimag g magnitude from APASS (13)
719
+ #32 53-54 (4) I*2 millimag r magnitude from APASS (13)
720
+ #33 55-56 (5) I*2 millimag i magnitude from APASS (13)
721
+ #34 57 apase I*1 1/100 mag error of B magnitude from APASS (14)
722
+ #35 58 (2) I*1 1/100 mag error of V magnitude from APASS (14)
723
+ #36 59 (3) I*1 1/100 mag error of g magnitude from APASS (14)
724
+ #37 60 (4) I*1 1/100 mag error of r magnitude from APASS (14)
725
+ #38 61 (5) I*1 1/100 mag error of i magnitude from APASS (14)
726
+ # Note (13): Data are from the AAVSO Photometric all-sky survey (APASS)
727
+ # DR6 plus single observation stars kindly provided by A.Henden.
728
+ # A magnitude entry of 20000 indicates "no data". For bright stars
729
+ # the apasm(1) = B mag and apasm(2) = V mag columns contain the
730
+ # Hipparcos/Tycho Bt and Vt mags respectively, whenever there is no
731
+ # APASS B or V available and valid Bt or Vt mags were found.
732
+ # For the bright supplement stars the same was done. All thses cases
733
+ # are identified by apasm(1) < 20000 and apase(1) = 0 for B mags,
734
+ # and similarly for apasm(2) < 20000 and apase(2) = 0 for V mags.
735
+ # For over 10,000 stars no Vt mag was available and the V mag from Tycho
736
+ # was used instead.
737
+ #
738
+ # Note (14): Positive errors are from the official release data error
739
+ # estimates (at least 2 observations per star). Formal, S/N estimated
740
+ # errors for single observations are multiplied by -1 for this column.
741
+ # The valid range for each APASS magnitude error is +-90 = +-0.90 mag.
742
+ # For "no data" (i.e. magnitude = 20000 = 20.0 mag) the error is set to 99.
743
+ # ============================================================================
744
+ # APASS is described in:
745
+ #
746
+ # Henden, A. A., et al. 2009, The AAVSO Photometric All-Sky Survey,
747
+ # AAS 214, 0702.
748
+ #
749
+ # Henden, A. A., et al. 2010, New Results from the AAVSO Photometric
750
+ # All Sky Survey, AAS 215, 47011.
751
+ #
752
+ # Henden, A. A., et al. 2011,The AAVSO Photometric All-Sky Survey,
753
+ # in prep.
754
+ #
755
+ # Smith, T. C., et al. 2010, AAVSO Photometric All-Sky Survey
756
+ # Implementation at the Dark Ridge Observatory, SAS.
757
+ #
758
+ # APASS provides magnitudes in five pass bands: Johnson B and V, and Sloan
759
+ # g', r', and i'.
760
+ #
761
+ # The Johnson system is described in:
762
+ #
763
+ # Johnson, H.L. and Morgan, W.W. 1953, The Astrophysical Journal, 117,
764
+ # 313
765
+ #
766
+ # Johnson filter transmission data can be found at:
767
+ #
768
+ # http://obswww.unige.ch/gcpd/filters/fil01.html
769
+ #
770
+ # ftp://obsftp.unige.ch/pub/mermio/filters/ph01.Bj
771
+ # ftp://obsftp.unige.ch/pub/mermio/filters/ph01.Vj
772
+ #
773
+ # The SDSS photometric system is described in:
774
+ #
775
+ # Fukugita, M. et al. 1996, The Astronomical Journal, 111, 1748
776
+ #
777
+ # SDSS filter transmission data can be found at:
778
+ #
779
+ # http://www.sdss.org/dr1/instruments/imager/index.html#filters
780
+ #
781
+ # http://www.sdss.org/dr1/instruments/imager/filters/g.dat
782
+ # http://www.sdss.org/dr1/instruments/imager/filters/r.dat
783
+ # http://www.sdss.org/dr1/instruments/imager/filters/i.dat
784
+ #
785
+ # The Tycho-2 photometric system is described in:
786
+ #
787
+ # The Hipparcos and Tycho Catalogues, ESA SP-1200, Vol. 1, June 1997.
788
+ #
789
+ # Bt and Vt filter transmission data is shown in Table 1.3.1 of SP-1200.
790
+ #
791
+ # ESA SP-1200 p. 57 provides the following conversion from Tycho V_T and B_T
792
+ # to Johnson V, B:
793
+ #
794
+ # V_J = V_T - 0.090 * (B_T - V_T)
795
+ # (B_J - V_J) = 0.850 * (B_T - V_T)
796
+ # or
797
+ # B_J = V_J + 0.850 * (B_T - V_T)
798
+ #
799
+ # These transformations fail for M-type stars and apply only to unreddened
800
+ # stars.
801
+ if parsed[28] != 20000:
802
+ star.apass_mag_b = parsed[28] * .001
803
+ if parsed[29] != 20000:
804
+ star.apass_mag_v = parsed[29] * .001
805
+ if parsed[30] != 20000:
806
+ star.apass_mag_g = parsed[30] * .001
807
+ if parsed[31] != 20000:
808
+ star.apass_mag_r = parsed[31] * .001
809
+ if parsed[32] != 20000:
810
+ star.apass_mag_i = parsed[32] * .001
811
+ star.apass_mag_b_sigma = parsed[33] * .01
812
+ star.apass_mag_v_sigma = parsed[34] * .01
813
+ star.apass_mag_g_sigma = parsed[35] * .01
814
+ star.apass_mag_r_sigma = parsed[36] * .01
815
+ star.apass_mag_i_sigma = parsed[37] * .01
816
+
817
+ star.johnson_mag_b = star.apass_mag_b
818
+ star.johnson_mag_v = star.apass_mag_v
819
+
820
+ if (parsed[28] < 20000 and parsed[33] == 0 and
821
+ parsed[29] < 20000 and parsed[34] == 0):
822
+ star.johnson_mag_v = (star.apass_mag_v -
823
+ 0.09 * (star.apass_mag_b -
824
+ star.apass_mag_v))
825
+ star.johnson_mag_b = (star.johnson_mag_v +
826
+ 0.85 * (star.apass_mag_b -
827
+ star.apass_mag_v))
828
+
829
+ #29 47-48 apasm I*2 millimag B magnitude from APASS (13)
830
+ #30 49-50 (2) I*2 millimag V magnitude from APASS (13)
831
+ #31 51-52 (3) I*2 millimag g magnitude from APASS (13)
832
+ #32 53-54 (4) I*2 millimag r magnitude from APASS (13)
833
+ #33 55-56 (5) I*2 millimag i magnitude from APASS (13)
834
+ #34 57 apase I*1 1/100 mag error of B magnitude from APASS (14)
835
+ #35 58 (2) I*1 1/100 mag error of V magnitude from APASS (14)
836
+ #36 59 (3) I*1 1/100 mag error of g magnitude from APASS (14)
837
+ #37 60 (4) I*1 1/100 mag error of r magnitude from APASS (14)
838
+ #38 61 (5) I*1 1/100 mag error of i magnitude from APASS (14)
839
+
840
+
841
+ #######################
842
+ # CATALOG MATCH FLAGS #
843
+ #######################
844
+
845
+ #39 62 gcflg I*1 Yale SPM g-flag*10 c-flag (15)
846
+ #40 63-66 icf(1) I*4 FK6-Hipparcos-Tycho source flag (16)
847
+ #41 icf(2) .. AC2000 catalog match flag (17)
848
+ #42 icf(3) .. AGK2 Bonn catalog match flag (17)
849
+ #43 icf(4) .. AKG2 Hamburg catalog match flag (17)
850
+ #44 icf(5) .. Zone Astrog. catalog match flag (17)
851
+ #45 icf(6) .. Black Birch catalog match flag (17)
852
+ #46 icf(7) .. Lick Astrog. catalog match flag (17)
853
+ #47 icf(8) .. NPM Lick catalog match flag (17)
854
+ #48 icf(9) .. SPM YSJ1 catalog match flag (17)
855
+ #
856
+ # Note (15): The g-flag from the Yale San Juan first epoch Southern
857
+ # Proper Motion data (YSJ1, SPM) has the following meaning:
858
+ #
859
+ # 0 = no info
860
+ # 1 = matched with 2MASS extended source list
861
+ # 2 = LEDA galaxy
862
+ # 3 = known QSO
863
+ #
864
+ # The c-flag from the Yale San Juan first epoch Southern
865
+ # Proper Motion data (YSJ1, SPM) indicates which input catalog
866
+ # has been used to identify stars for pipeline processing:
867
+ #
868
+ # 1 = Hipparcos
869
+ # 2 = Tycho2
870
+ # 3 = UCAC2
871
+ # 4 = 2MASS psc
872
+ # 5 = 2MASS xsc (extended sources, largely (but not all!) galaxies)
873
+ # 6 = LEDA (confirmed galaxies, Paturel et al. 2005)
874
+ # 7 = QSO (Veron-Cetty & Veron 2006)
875
+ # Note (16, 17) binary data: a single 4-byte integer is used to store
876
+ # the 10 flags of "icf". That 4-byte integer has the value:
877
+ # icf = icf(1)*10^8 + icf(2)*10^7 + ... + icf(8)*10 + icf(9)
878
+ #
879
+ # Note (16): The FK6-Hipparcos-Tycho-source-flag has the following meaning:
880
+ # (= icf(1))
881
+ # 0 = not a Hip. or Tycho star
882
+ # 1 = Hipparcos 1997 version main catalog (not in UCAC4 data files)
883
+ # 2 = Hipparcos double star annex
884
+ # 3 = Tycho-2
885
+ # 4 = Tycho annex 1
886
+ # 5 = Tycho annex 2
887
+ # 6 = FK6 position and proper motion (instead of Hipparcos data)
888
+ # 7 = Hippparcos 2007 solution position and proper motion
889
+ # 8 = FK6 only PM substit. (not in UCAC4 data)
890
+ # 9 = Hipparcos 2007, only proper motion substituted
891
+ #
892
+ # Note (17): The catflg match flag is provided for major catalogs used
893
+ # in the computation of the proper motions. Each match is analyzed
894
+ # for multiple matches of entries of the 1st catalog to 2nd catalog
895
+ # entries, and the other way around. Matches are also classified
896
+ # by separation and difference in magnitude to arrive at a confidence
897
+ # level group. The flag has the following meaning:
898
+ #
899
+ # 0 = star not matched with this catalog
900
+ # 1 = unique-unique match, not involving a double star
901
+ # 2 = ... same, but involving a flagged double star
902
+ # 3 = multiple match but unique in high confidence level group, no double
903
+ # 4 = ... same, but involving a flagged double star
904
+ # 5 = closest match, not involving a double, likely o.k.
905
+ # 6 = ... same, but involving a flagged double star
906
+ # 7 = maybe o.k. smallest sep. match in both directions, no double
907
+ # 8 = ... same, but involving a flagged double star
908
+ star.cat_match = [int(x) for x in ('%010d' % parsed[39])]
909
+
910
+ ###################
911
+ # UCAC4 UNIQUE ID #
912
+ ###################
913
+
914
+ #(43)51 69-72 rnm I*4 unique star identification number (20)
915
+ # Note (20): This unique star identification number is between 200001
916
+ # and 321640 for Hipparcos stars, and between 1 and 9430 for non-
917
+ # Hipparcos stars supplemented to the UCAC4 catalog (no CCD observ.).
918
+ # For all other stars this unique star identification number is the
919
+ # internal mean-position-file (MPOS) number + 1 million.
920
+ # For both the Hipparcos and the supplement stars there is an entry
921
+ # on the u4supl.dat file providing more information, including the
922
+ # original Hipparcos star number. Note, there are several thousand
923
+ # cases where different UCAC4 stars link to the same Hipparcos star
924
+ # number due to resolved binary stars with each component being a
925
+ # separate star entry in UCAC4.
926
+ star.unique_number = parsed[42]
927
+
928
+ ###############################
929
+ # UCAC2 IDENTIFICATION NUMBER #
930
+ ###############################
931
+
932
+ #(44)52 73-74 zn2 I*2 zone number of UCAC2 (0 = no match) (21)
933
+ #(45)53 75-78 rn2 I*4 running record number along UCAC2 zone (21)
934
+
935
+ if parsed[43] == 0:
936
+ star.id_str_ucac2 = None
937
+ else:
938
+ star.id_str_ucac2 = 'UCAC2-%03d-%06d' % (parsed[43],
939
+ parsed[44])
940
+
941
+ ###############################
942
+ # UCAC4 IDENTIFICATION NUMBER #
943
+ ###############################
944
+
945
+ star.id_str = 'UCAC4-%03d-%06d' % (znum, rec_num)
946
+
947
+ ##################################################
948
+ # COMPUTE SPECTRAL CLASS AND SURFACE TEMPERATURE #
949
+ ##################################################
950
+
951
+ if (star.johnson_mag_b is not None and
952
+ star.johnson_mag_v is not None):
953
+ star.spectral_class = self.sclass_from_bv(star.johnson_mag_b,
954
+ star.johnson_mag_v)
955
+
956
+ if star.spectral_class is not None:
957
+ star.temperature = self.temperature_from_sclass(star.
958
+ spectral_class)
959
+
960
+ if self.debug_level:
961
+ print('ID', parsed[42], 'OK!')
962
+ print(star)
963
+ yield star
964
+
965
+ #############################################################################
966
+
967
+ def _zone_filename(self, znum):
968
+ """Convert a UCAC4 zone number to an absolute pathspec."""
969
+ fn = os.path.join(self.dirname, 'u4b', 'z%03d'%znum)
970
+ return fn
971
+
972
+ def _find_starting_ra(self, fp, ra_min):
973
+ """Efficiently find the first record >= RA_MIN."""
974
+ if ra_min <= 0.:
975
+ # No point in searching!
976
+ return 0
977
+
978
+ fp.seek(0, os.SEEK_END)
979
+ file_size = fp.tell()
980
+ num_rec = file_size // UCAC4_RECORD_SIZE
981
+ assert num_rec * UCAC4_RECORD_SIZE == file_size
982
+
983
+ lo = 0
984
+ hi = num_rec-1
985
+ while lo <= hi:
986
+ mid = (lo+hi)//2
987
+ fp.seek(mid*UCAC4_RECORD_SIZE, os.SEEK_SET)
988
+ record = fp.read(UCAC4_RECORD_SIZE_RA)
989
+ parsed = struct.unpack(UCAC4_FMT_RA, record)
990
+ midval = parsed[0] * MAS_TO_RAD
991
+ if midval < ra_min:
992
+ lo = mid+1
993
+ elif midval > ra_min:
994
+ hi = mid-1
995
+ else:
996
+ # Exact match!
997
+ fp.seek(mid*UCAC4_RECORD_SIZE, os.SEEK_SET)
998
+ return mid // UCAC4_RECORD_SIZE
999
+
1000
+ # At this point lo is the best we can do
1001
+ 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)