rms-starcat 1.0.2__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.
- rms_starcat-1.0.2.dist-info/METADATA +154 -0
- rms_starcat-1.0.2.dist-info/RECORD +12 -0
- rms_starcat-1.0.2.dist-info/WHEEL +5 -0
- rms_starcat-1.0.2.dist-info/licenses/LICENSE +201 -0
- rms_starcat-1.0.2.dist-info/top_level.txt +1 -0
- starcat/__init__.py +31 -0
- starcat/_version.py +34 -0
- starcat/py.typed +0 -0
- starcat/spice.py +94 -0
- starcat/starcatalog.py +530 -0
- starcat/ucac4.py +1138 -0
- starcat/ybsc.py +638 -0
starcat/starcatalog.py
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
################################################################################
|
|
2
|
+
# starcat/starcatalog.py
|
|
3
|
+
################################################################################
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Iterator
|
|
8
|
+
import inspect
|
|
9
|
+
import numpy as np
|
|
10
|
+
from typing import Any, Optional, no_type_check
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
AS_TO_DEG = 1 / 3600.
|
|
14
|
+
AS_TO_RAD = np.radians(AS_TO_DEG)
|
|
15
|
+
MAS_TO_DEG = AS_TO_DEG / 1000.
|
|
16
|
+
MAS_TO_RAD = np.radians(MAS_TO_DEG)
|
|
17
|
+
YEAR_TO_SEC = 1 / 365.25 / 86400.
|
|
18
|
+
|
|
19
|
+
TWOPI = 2 * np.pi
|
|
20
|
+
HALFPI = np.pi / 2
|
|
21
|
+
|
|
22
|
+
#===============================================================================
|
|
23
|
+
#
|
|
24
|
+
# Jacobson B-V photometry vs. stellar spectral classification
|
|
25
|
+
#
|
|
26
|
+
# Data from
|
|
27
|
+
# Zombeck, M. V. Handbook of Space Astronomy and Astrophysics,
|
|
28
|
+
# Cambridge, UK: Cambridge University Press, 2nd ed., pp. 68-70
|
|
29
|
+
# http://ads.harvard.edu/books/hsaa/
|
|
30
|
+
# as transcribed:
|
|
31
|
+
# http://www.vendian.org/mncharity/dir3/starcolor/details.html
|
|
32
|
+
#
|
|
33
|
+
# The tables below only include main sequence stars, but the temperature
|
|
34
|
+
# difference between main sequence stars and giant stars is minimal for our
|
|
35
|
+
# purposes. Missing values have been linearly interpolated.
|
|
36
|
+
#
|
|
37
|
+
#===============================================================================
|
|
38
|
+
|
|
39
|
+
SCLASS_TO_B_MINUS_V = {
|
|
40
|
+
'O5': -0.32,
|
|
41
|
+
'O6': -0.32,
|
|
42
|
+
'O7': -0.32,
|
|
43
|
+
'O8': -0.31,
|
|
44
|
+
'O9': -0.31,
|
|
45
|
+
'O9.5': -0.30,
|
|
46
|
+
'B0': -0.30,
|
|
47
|
+
'B0.5': -0.28,
|
|
48
|
+
'B1': -0.26,
|
|
49
|
+
'B2': -0.24,
|
|
50
|
+
'B3': -0.20,
|
|
51
|
+
'B4': -0.18, # Interpolated
|
|
52
|
+
'B5': -0.16,
|
|
53
|
+
'B6': -0.14,
|
|
54
|
+
'B7': -0.12,
|
|
55
|
+
'B8': -0.09,
|
|
56
|
+
'B9': -0.06,
|
|
57
|
+
'A0': +0.00,
|
|
58
|
+
'A1': +0.02, # Interpolated
|
|
59
|
+
'A2': +0.04, # Interpolated
|
|
60
|
+
'A3': +0.06,
|
|
61
|
+
'A4': +0.10, # Interpolated
|
|
62
|
+
'A5': +0.14,
|
|
63
|
+
'A6': +0.16, # Interpolated
|
|
64
|
+
'A7': +0.19,
|
|
65
|
+
'A8': +0.23, # Interpolated
|
|
66
|
+
'A9': +0.27, # Interpolated
|
|
67
|
+
'F0': +0.31,
|
|
68
|
+
'F1': +0.33, # Interpolated
|
|
69
|
+
'F2': +0.36,
|
|
70
|
+
'F3': +0.38, # Interpolated
|
|
71
|
+
'F4': +0.41, # Interpolated
|
|
72
|
+
'F5': +0.43,
|
|
73
|
+
'F6': +0.47, # Interpolated
|
|
74
|
+
'F7': +0.51, # Interpolated
|
|
75
|
+
'F8': +0.54,
|
|
76
|
+
'F9': +0.56, # Interpolated
|
|
77
|
+
'G0': +0.59,
|
|
78
|
+
'G1': +0.61, # Interpolated
|
|
79
|
+
'G2': +0.63,
|
|
80
|
+
'G3': +0.64, # Interpolated
|
|
81
|
+
'G4': +0.65, # Interpolated
|
|
82
|
+
'G5': +0.66,
|
|
83
|
+
'G6': +0.69, # Interpolated
|
|
84
|
+
'G7': +0.72, # Interpolated
|
|
85
|
+
'G8': +0.74,
|
|
86
|
+
'G9': +0.78, # Interpolated
|
|
87
|
+
'K0': +0.82,
|
|
88
|
+
'K1': +0.87, # Interpolated
|
|
89
|
+
'K2': +0.92,
|
|
90
|
+
'K3': +0.99, # Interpolated
|
|
91
|
+
'K4': +1.07, # Interpolated
|
|
92
|
+
'K5': +1.15,
|
|
93
|
+
'K6': +1.22, # Interpolated
|
|
94
|
+
'K7': +1.30,
|
|
95
|
+
'K8': +1.33, # Interpolated
|
|
96
|
+
'K9': +1.37, # Interpolated
|
|
97
|
+
'M0': +1.41,
|
|
98
|
+
'M1': +1.48,
|
|
99
|
+
'M2': +1.52,
|
|
100
|
+
'M3': +1.55,
|
|
101
|
+
'M4': +1.56,
|
|
102
|
+
'M5': +1.61,
|
|
103
|
+
'M6': +1.72,
|
|
104
|
+
'M7': +1.84,
|
|
105
|
+
'M8': +2.00
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
SCLASS_TO_SURFACE_TEMP = {
|
|
109
|
+
'O5': 38000,
|
|
110
|
+
'O6': 38000,
|
|
111
|
+
'O7': 38000,
|
|
112
|
+
'O8': 35000,
|
|
113
|
+
'O9': 35000,
|
|
114
|
+
'O9.5': 31900,
|
|
115
|
+
'B0': 30000,
|
|
116
|
+
'B0.5': 27000,
|
|
117
|
+
'B1': 24200,
|
|
118
|
+
'B2': 22100,
|
|
119
|
+
'B3': 18800,
|
|
120
|
+
'B4': 17600, # Interpolated
|
|
121
|
+
'B5': 16400,
|
|
122
|
+
'B6': 15400,
|
|
123
|
+
'B7': 14500,
|
|
124
|
+
'B8': 13400,
|
|
125
|
+
'B9': 12400,
|
|
126
|
+
'A0': 10800,
|
|
127
|
+
'A1': 10443, # Interpolated
|
|
128
|
+
'A2': 10086, # Interpolated
|
|
129
|
+
'A3': 9730,
|
|
130
|
+
'A4': 9175, # Interpolated
|
|
131
|
+
'A5': 8620,
|
|
132
|
+
'A6': 8405, # Interpolated
|
|
133
|
+
'A7': 8190,
|
|
134
|
+
'A8': 7873, # Interpolated
|
|
135
|
+
'A9': 7557, # Interpolated
|
|
136
|
+
'F0': 7240,
|
|
137
|
+
'F1': 7085, # Interpolated
|
|
138
|
+
'F2': 6930,
|
|
139
|
+
'F3': 6800, # Interpolated
|
|
140
|
+
'F4': 6670, # Interpolated
|
|
141
|
+
'F5': 6540,
|
|
142
|
+
'F6': 6427, # Interpolated
|
|
143
|
+
'F7': 6313, # Interpolated
|
|
144
|
+
'F8': 6200,
|
|
145
|
+
'F9': 6060, # Interpolated
|
|
146
|
+
'G0': 5920,
|
|
147
|
+
'G1': 5850, # Interpolated
|
|
148
|
+
'G2': 5780,
|
|
149
|
+
'G3': 5723, # Interpolated
|
|
150
|
+
'G4': 5667, # Interpolated
|
|
151
|
+
'G5': 5610,
|
|
152
|
+
'G6': 5570, # Interpolated
|
|
153
|
+
'G7': 5530, # Interpolated
|
|
154
|
+
'G8': 5490,
|
|
155
|
+
'G9': 5365, # Interpolated
|
|
156
|
+
'K0': 5240,
|
|
157
|
+
'K1': 5010, # Interpolated
|
|
158
|
+
'K2': 4780,
|
|
159
|
+
'K3': 4706, # Interpolated
|
|
160
|
+
'K4': 4632, # Interpolated
|
|
161
|
+
'K5': 4558, # Interpolated
|
|
162
|
+
'K6': 4484, # Interpolated
|
|
163
|
+
'K7': 4410,
|
|
164
|
+
'K8': 4247, # Interpolated
|
|
165
|
+
'K9': 4083, # Interpolated
|
|
166
|
+
'M0': 3800, # M class from https://arxiv.org/abs/0903.3371
|
|
167
|
+
'M1': 3600,
|
|
168
|
+
'M2': 3400,
|
|
169
|
+
'M3': 3250,
|
|
170
|
+
'M4': 3100,
|
|
171
|
+
'M5': 2800,
|
|
172
|
+
'M6': 2600,
|
|
173
|
+
'M7': 2500,
|
|
174
|
+
'M8': 2300,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
#===============================================================================
|
|
179
|
+
#
|
|
180
|
+
# STAR Superclass
|
|
181
|
+
#
|
|
182
|
+
#===============================================================================
|
|
183
|
+
|
|
184
|
+
class Star:
|
|
185
|
+
"""A holder for star attributes.
|
|
186
|
+
|
|
187
|
+
This is the base class that defines attributes common to all or most
|
|
188
|
+
star catalogs. Note that fields vary among star catalogs and individual
|
|
189
|
+
stars and there is no guarantee a particular field will be filled in.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def __init__(self) -> None:
|
|
193
|
+
"""Constructor for Star; additional attributes are available from subclasses."""
|
|
194
|
+
|
|
195
|
+
self.unique_number: Optional[int] = None
|
|
196
|
+
"""Unique catalog number (may not be unique across catalogs)"""
|
|
197
|
+
|
|
198
|
+
self.ra: Optional[float] = None
|
|
199
|
+
"""Right ascension at J2000 epoch (radians)"""
|
|
200
|
+
|
|
201
|
+
self.ra_sigma: Optional[float] = None
|
|
202
|
+
"""Right ascension uncertainty (radians)"""
|
|
203
|
+
|
|
204
|
+
self.rac_sigma: Optional[float] = None
|
|
205
|
+
"""Right ascension * cos(DEC) uncertainty (radians)"""
|
|
206
|
+
|
|
207
|
+
self.dec: Optional[float] = None
|
|
208
|
+
"""Declination at J2000 epoch (radians)"""
|
|
209
|
+
|
|
210
|
+
self.dec_sigma: Optional[float] = None
|
|
211
|
+
"""Declination uncertainty (radians)"""
|
|
212
|
+
|
|
213
|
+
self.vmag: Optional[float] = None
|
|
214
|
+
"""Visual magnitude"""
|
|
215
|
+
|
|
216
|
+
self.vmag_sigma: Optional[float] = None
|
|
217
|
+
"""Visual magnitude uncertainty"""
|
|
218
|
+
|
|
219
|
+
self.pm_ra: Optional[float] = None
|
|
220
|
+
"""Proper motion in RA (radians/sec)"""
|
|
221
|
+
|
|
222
|
+
self.pm_ra_sigma: Optional[float] = None
|
|
223
|
+
"""Proper motion in RA uncertainty (radians/sec)"""
|
|
224
|
+
|
|
225
|
+
self.pm_rac: Optional[float] = None
|
|
226
|
+
"""Proper motion in RA * cos(DEC) (radians/sec)"""
|
|
227
|
+
|
|
228
|
+
self.pm_rac_sigma: Optional[float] = None
|
|
229
|
+
"""Proper motion in RA * cos(DEC) uncertainty (radians/sec)"""
|
|
230
|
+
|
|
231
|
+
self.pm_dec: Optional[float] = None
|
|
232
|
+
"""Proper motion in DEC (radians/sec)"""
|
|
233
|
+
|
|
234
|
+
self.pm_dec_sigma: Optional[float] = None
|
|
235
|
+
"""Proper motion in DEC error (radians/sec)"""
|
|
236
|
+
|
|
237
|
+
self.spectral_class: Optional[str] = None
|
|
238
|
+
"""Spectral class"""
|
|
239
|
+
|
|
240
|
+
self.temperature: Optional[float] = None
|
|
241
|
+
"""Star temperature (usually derived from spectral class)"""
|
|
242
|
+
|
|
243
|
+
def __str__(self) -> str:
|
|
244
|
+
|
|
245
|
+
ret = f'UNIQUE ID {self.unique_number:d}'
|
|
246
|
+
|
|
247
|
+
if self.ra is not None:
|
|
248
|
+
ret += f' | RA {np.degrees(self.ra):.7f}°'
|
|
249
|
+
if self.ra_sigma is not None:
|
|
250
|
+
ret += f' [+/- {np.degrees(self.ra_sigma):.7f}°]'
|
|
251
|
+
|
|
252
|
+
ra_deg = np.degrees(self.ra)/15 # In hours
|
|
253
|
+
hh = int(ra_deg)
|
|
254
|
+
mm = int((ra_deg-hh)*60)
|
|
255
|
+
ss = (ra_deg-hh-mm/60.)*3600
|
|
256
|
+
ret += f' ({hh:02d}h{mm:02d}m{ss:05.3f}s'
|
|
257
|
+
if self.ra_sigma is not None:
|
|
258
|
+
ret += ' +/- %.4fs' % (np.degrees(self.ra_sigma)*3600)
|
|
259
|
+
ret += ')'
|
|
260
|
+
|
|
261
|
+
if self.dec is not None:
|
|
262
|
+
ret += f' | DEC {np.degrees(self.dec):.7f}°'
|
|
263
|
+
if self.dec_sigma is not None:
|
|
264
|
+
ret += f' [+/- {np.degrees(self.dec_sigma):.7f}°]'
|
|
265
|
+
|
|
266
|
+
dec_deg = np.degrees(self.dec)
|
|
267
|
+
neg = '+'
|
|
268
|
+
if dec_deg < 0.:
|
|
269
|
+
neg = '-'
|
|
270
|
+
dec_deg = -dec_deg
|
|
271
|
+
dd = int(dec_deg)
|
|
272
|
+
mm = int((dec_deg-dd)*60)
|
|
273
|
+
ss = (dec_deg-dd-mm/60.)*3600
|
|
274
|
+
ret += f' ({neg}{dd:03d}d{mm:02d}m{ss:05.3f}s'
|
|
275
|
+
|
|
276
|
+
if self.dec_sigma is not None:
|
|
277
|
+
ret += ' +/- %.4fs' % (np.degrees(self.dec_sigma)*3600)
|
|
278
|
+
ret += ')'
|
|
279
|
+
|
|
280
|
+
ret += '\n'
|
|
281
|
+
|
|
282
|
+
if self.vmag is not None:
|
|
283
|
+
ret += f'VMAG {self.vmag:6.3f} '
|
|
284
|
+
if self.vmag_sigma is not None:
|
|
285
|
+
ret += f'+/- {self.vmag_sigma:6.3f} '
|
|
286
|
+
|
|
287
|
+
if self.pm_ra is not None:
|
|
288
|
+
ret += ' | PM RA %.3f mas/yr ' % (self.pm_ra / MAS_TO_RAD / YEAR_TO_SEC)
|
|
289
|
+
if self.pm_ra_sigma:
|
|
290
|
+
ret += '+/- %.3f ' % (self.pm_ra_sigma / MAS_TO_RAD / YEAR_TO_SEC)
|
|
291
|
+
|
|
292
|
+
if self.pm_dec is not None:
|
|
293
|
+
ret += ' | PM DEC %.3f mas/yr ' % (self.pm_dec / MAS_TO_RAD / YEAR_TO_SEC)
|
|
294
|
+
if self.pm_dec_sigma:
|
|
295
|
+
ret += '+/- %.3f ' % (self.pm_dec_sigma / MAS_TO_RAD / YEAR_TO_SEC)
|
|
296
|
+
|
|
297
|
+
ret += '\n'
|
|
298
|
+
|
|
299
|
+
if self.temperature is None:
|
|
300
|
+
ret += 'TEMP N/A'
|
|
301
|
+
else:
|
|
302
|
+
ret += f'TEMP {self.temperature:5d}'
|
|
303
|
+
ret += f' | SCLASS {self.spectral_class:s}'
|
|
304
|
+
|
|
305
|
+
return ret
|
|
306
|
+
|
|
307
|
+
# This is a stupid thing to do, but it's necessary to avoid mypy from complaining
|
|
308
|
+
# about missing attributes. mypy ignores attributes for classes that have a
|
|
309
|
+
# __getattr__ method.
|
|
310
|
+
@no_type_check
|
|
311
|
+
def __getattr__(self, name: str) -> Any:
|
|
312
|
+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
|
|
313
|
+
|
|
314
|
+
def to_dict(self) -> dict[str, Any]:
|
|
315
|
+
"""Return a dictionary containing all star attributes."""
|
|
316
|
+
|
|
317
|
+
attribs = inspect.getmembers(self, lambda a: not inspect.isroutine(a))
|
|
318
|
+
attribs = [a for a in attribs
|
|
319
|
+
if not (a[0].startswith('__') and a[0].endswith('__'))]
|
|
320
|
+
return dict(attribs)
|
|
321
|
+
|
|
322
|
+
def from_dict(self, d: dict[str, Any]) -> None:
|
|
323
|
+
"""Set the attributes for this star based on the dictionary."""
|
|
324
|
+
|
|
325
|
+
for key in list(d.keys()):
|
|
326
|
+
setattr(self, key, d[key])
|
|
327
|
+
|
|
328
|
+
def ra_dec_with_pm(self, tdb: float) -> tuple[float, float] | tuple[None, None]:
|
|
329
|
+
"""Return the star's RA and DEC adjusted for proper motion.
|
|
330
|
+
|
|
331
|
+
If no proper motion is available, the original RA and DEC are returned.
|
|
332
|
+
|
|
333
|
+
Parameters:
|
|
334
|
+
tdb: The time since the J2000 epoch in seconds.
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
A tuple containing the RA and DEC adjusted for proper motion, if possible.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
if self.ra is None or self.dec is None:
|
|
341
|
+
return (None, None)
|
|
342
|
+
|
|
343
|
+
if self.pm_ra is None or self.pm_dec is None:
|
|
344
|
+
return (self.ra, self.dec)
|
|
345
|
+
|
|
346
|
+
return (self.ra + tdb*self.pm_ra, self.dec + tdb*self.pm_dec)
|
|
347
|
+
|
|
348
|
+
@staticmethod
|
|
349
|
+
def temperature_from_sclass(sclass: Optional[str]) -> float | None:
|
|
350
|
+
"""Return a star's temperature (K) given its spectral class.
|
|
351
|
+
|
|
352
|
+
Parameters:
|
|
353
|
+
sclass: The spectral class.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
The temperature associated with the spectral class.
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
if sclass is None:
|
|
360
|
+
return None
|
|
361
|
+
if sclass.endswith('*'): # This happens on some SPICE catalog stars
|
|
362
|
+
sclass = sclass[:-1]
|
|
363
|
+
sclass = sclass.strip().upper()
|
|
364
|
+
try:
|
|
365
|
+
return SCLASS_TO_SURFACE_TEMP[sclass]
|
|
366
|
+
except KeyError:
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
@staticmethod
|
|
370
|
+
def bmv_from_sclass(sclass: str) -> float | None:
|
|
371
|
+
"""Return a star's B-V color given its spectral class.
|
|
372
|
+
|
|
373
|
+
Parameters:
|
|
374
|
+
sclass: The spectral class.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
The B-V color associated with the spectral class.
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
if sclass[-1] == '*': # This happens on some SPICE catalog stars
|
|
381
|
+
sclass = sclass[:-1]
|
|
382
|
+
sclass = sclass.strip().upper()
|
|
383
|
+
try:
|
|
384
|
+
return SCLASS_TO_B_MINUS_V[sclass]
|
|
385
|
+
except KeyError:
|
|
386
|
+
return None
|
|
387
|
+
|
|
388
|
+
@staticmethod
|
|
389
|
+
def sclass_from_bv(b: float,
|
|
390
|
+
v: float) -> str | None:
|
|
391
|
+
"""Return a star's spectral class given photometric B and V.
|
|
392
|
+
|
|
393
|
+
Parameters:
|
|
394
|
+
b: The photometric B value.
|
|
395
|
+
v: The photometric V value.
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
The spectral class, if available.
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
bmv = b - v
|
|
402
|
+
|
|
403
|
+
best_sclass = None
|
|
404
|
+
best_resid = 1e38
|
|
405
|
+
|
|
406
|
+
min_bmv = 1e38
|
|
407
|
+
max_bmv = -1e38
|
|
408
|
+
for sclass, sbmv in SCLASS_TO_B_MINUS_V.items():
|
|
409
|
+
min_bmv = min(min_bmv, sbmv)
|
|
410
|
+
max_bmv = max(max_bmv, sbmv)
|
|
411
|
+
resid = abs(sbmv-bmv)
|
|
412
|
+
if resid < best_resid:
|
|
413
|
+
best_resid = resid
|
|
414
|
+
best_sclass = sclass
|
|
415
|
+
|
|
416
|
+
if min_bmv <= bmv <= max_bmv:
|
|
417
|
+
return best_sclass
|
|
418
|
+
|
|
419
|
+
return None
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class StarCatalog:
|
|
423
|
+
def __init__(self) -> None:
|
|
424
|
+
self.debug_level = 0
|
|
425
|
+
|
|
426
|
+
def count_stars(self, **kwargs: Any) -> int:
|
|
427
|
+
"""Count the stars that match the given search criteria."""
|
|
428
|
+
|
|
429
|
+
count = 0
|
|
430
|
+
for _ in self.find_stars(full_result=False, **kwargs):
|
|
431
|
+
count += 1
|
|
432
|
+
return count
|
|
433
|
+
|
|
434
|
+
def find_stars(self,
|
|
435
|
+
ra_min: float = 0,
|
|
436
|
+
ra_max: float = TWOPI,
|
|
437
|
+
dec_min: float = -HALFPI,
|
|
438
|
+
dec_max: float = HALFPI,
|
|
439
|
+
vmag_min: Optional[float] = None,
|
|
440
|
+
vmag_max: Optional[float] = None,
|
|
441
|
+
full_result: bool = True,
|
|
442
|
+
**kwargs: Any) -> Iterator[Star]:
|
|
443
|
+
"""Yield the stars that match the given search criteria.
|
|
444
|
+
|
|
445
|
+
Parameters:
|
|
446
|
+
ra_min: The minimum RA.
|
|
447
|
+
ra_max: The maximum RA.
|
|
448
|
+
dec_min: The minimum DEC.
|
|
449
|
+
dec_max: The maximum DEC.
|
|
450
|
+
vmag_min: The minimum visual magnitude.
|
|
451
|
+
vmag_max: The maximum visual magnitude.
|
|
452
|
+
full_result: If True, fill in all available fields of the resulting
|
|
453
|
+
:class:`Star`. If False, some fields will not be filled in to save
|
|
454
|
+
time. This is most useful when counting stars.
|
|
455
|
+
|
|
456
|
+
Yields:
|
|
457
|
+
The :class:`Star` objects that meet the given constraints.
|
|
458
|
+
"""
|
|
459
|
+
|
|
460
|
+
ra_min = np.clip(ra_min, 0., TWOPI)
|
|
461
|
+
ra_max = np.clip(ra_max, 0., TWOPI)
|
|
462
|
+
dec_min = np.clip(dec_min, -HALFPI, HALFPI)
|
|
463
|
+
dec_max = np.clip(dec_max, -HALFPI, HALFPI)
|
|
464
|
+
|
|
465
|
+
if ra_min > ra_max:
|
|
466
|
+
if dec_min > dec_max:
|
|
467
|
+
# Split into four searches
|
|
468
|
+
for star in self._find_stars(0., ra_max, -HALFPI, dec_max,
|
|
469
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
470
|
+
full_result=full_result,
|
|
471
|
+
**kwargs):
|
|
472
|
+
yield star
|
|
473
|
+
for star in self._find_stars(ra_min, TWOPI, -HALFPI, dec_max,
|
|
474
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
475
|
+
full_result=full_result,
|
|
476
|
+
**kwargs):
|
|
477
|
+
yield star
|
|
478
|
+
for star in self._find_stars(0., ra_max, dec_min, HALFPI,
|
|
479
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
480
|
+
full_result=full_result,
|
|
481
|
+
**kwargs):
|
|
482
|
+
yield star
|
|
483
|
+
for star in self._find_stars(ra_min, TWOPI, dec_min, HALFPI,
|
|
484
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
485
|
+
full_result=full_result,
|
|
486
|
+
**kwargs):
|
|
487
|
+
yield star
|
|
488
|
+
else:
|
|
489
|
+
# Split into two searches - RA
|
|
490
|
+
for star in self._find_stars(0., ra_max, dec_min, dec_max,
|
|
491
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
492
|
+
full_result=full_result,
|
|
493
|
+
**kwargs):
|
|
494
|
+
yield star
|
|
495
|
+
for star in self._find_stars(ra_min, TWOPI, dec_min, dec_max,
|
|
496
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
497
|
+
full_result=full_result,
|
|
498
|
+
**kwargs):
|
|
499
|
+
yield star
|
|
500
|
+
else:
|
|
501
|
+
if dec_min > dec_max:
|
|
502
|
+
# Split into two searches - DEC
|
|
503
|
+
for star in self._find_stars(ra_min, ra_max, -HALFPI, dec_max,
|
|
504
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
505
|
+
full_result=full_result,
|
|
506
|
+
**kwargs):
|
|
507
|
+
yield star
|
|
508
|
+
for star in self._find_stars(ra_min, ra_max, dec_min, HALFPI,
|
|
509
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
510
|
+
full_result=full_result,
|
|
511
|
+
**kwargs):
|
|
512
|
+
yield star
|
|
513
|
+
else:
|
|
514
|
+
# No need to split at all
|
|
515
|
+
for star in self._find_stars(ra_min, ra_max, dec_min, dec_max,
|
|
516
|
+
vmag_min=vmag_min, vmag_max=vmag_max,
|
|
517
|
+
full_result=full_result,
|
|
518
|
+
**kwargs):
|
|
519
|
+
yield star
|
|
520
|
+
|
|
521
|
+
def _find_stars(self,
|
|
522
|
+
ra_min: float,
|
|
523
|
+
ra_max: float,
|
|
524
|
+
dec_min: float,
|
|
525
|
+
dec_max: float,
|
|
526
|
+
vmag_min: Optional[float] = None,
|
|
527
|
+
vmag_max: Optional[float] = None,
|
|
528
|
+
full_result: bool = True,
|
|
529
|
+
**kwargs: Any) -> Iterator[Star]:
|
|
530
|
+
raise NotImplementedError
|