22"""Utilities for interfacing with hpgeom. Originally implemented in
23http://github.com/LSSTDESC/dia_pipe and then translated to hpgeom.
26__all__ = [
"toIndex",
"toRaDec",
"eq2xyz",
"eq2xyzVec",
"convert_spherical",
27 "convert_spherical_array",
"query_disc",
"obj_id_to_ss_object_id",
"ss_object_id_to_obj_id"]
29from astropy.time
import Time
32import numpy.typing
as npt
36 """Return healpix index given ra, dec in degrees
41 Power of 2 nside healpix resolution.
45 Declination in degrees
50 Unique healpix pixel ID containing point RA, DEC at resolution nside.
52 return hpg.angle_to_pixel(nside, ra, dec, nest=
False)
56 """Convert from healpix index to ra,dec in degrees
61 Resolution of healpixel "grid".
63 Index of the healpix pixel we want to find the location of.
67 pos : `numpy.ndarray`, (2,)
68 RA and DEC of healpix pixel location in degrees.
70 ra, dec = hpg.pixel_to_angle(nside, index, nest=
False)
71 return np.dstack((ra, dec))[0]
75 """Convert from equatorial ra,dec in degrees to x,y,z on unit sphere.
82 Declination in degrees
86 xyz : `numpy.ndarray`, (3,)
87 Float xyz positions on the unit sphere.
90 theta = np.pi/2 - np.deg2rad(dec)
91 sintheta = np.sin(theta)
92 x = sintheta*np.cos(phi)
93 y = sintheta*np.sin(phi)
95 return np.array([x, y, z])
99 """Convert equatorial ra,dec in degrees to x,y,z on the unit sphere
102 Vectorized version of ``eq2xyz``
106 ra : array_like, (N,)
107 Array of RA in degrees.
108 dec : array_like, (N,)
109 Declination in degrees
113 vec : `numpy.ndarray`, (N,3)
114 Array of unitsphere 3-vectors.
116 ra = np.array(ra, dtype=
'f8', ndmin=1, copy=
False)
117 dec = np.array(dec, dtype=
'f8', ndmin=1, copy=
False)
118 if ra.size != dec.size:
119 raise ValueError(
"ra,dec not same size: %s,%s" % (ra.size, dec.size))
127 """Convert from ra,dec to spherical coordinates.
136 Declination in radians
138 return np.dstack([np.cos(dec*np.pi/180)*np.cos(ra*np.pi/180),
139 np.cos(dec*np.pi/180)*np.sin(ra*np.pi/180),
140 np.sin(dec*np.pi/180)])[0]
144 """Convert from and a array ra,dec to spherical coordinates.
150 array : `numpy.ndarray`, (N, 2)
151 (N, 2) Array of RA, DEC values.
155 vecs : `numpy.ndarray`, (N, 3)
156 Vectors on the unit sphere
164 """Get the list of healpix indices within max_rad, min_rad given in radians
165 around ra,dec given in degrees
170 Resolution of the healpixels to search/return.
174 Declination in degrees
176 Max distance in radians to search nearby healpixels.
177 min_rad : `float`, optional
178 Minimum distance in radians to search healpixels. Default = 0.
180 ra = np.atleast_1d(ra)
181 dec = np.atleast_1d(dec)
183 max_rad_deg = np.rad2deg(max_rad)
186 [hpg.query_circle(nside, a, b, max_rad_deg, nest=
False)
187 for (a, b)
in zip(ra, dec)])
189 if min_rad > 0
and len(pixels) > 0:
191 min_rad2 = min_rad**2
193 dsq = np.sum((vecs - vec0)**2, axis=1)
194 match = dsq > min_rad2
195 pixels = pixels[match]
201 """Convert from Minor Planet Center packed provisional object ID to
207 Minor Planet Center packed provisional designation for a small solar
208 system object. Must be fewer than eight characters.
218 Raised if either objID is shorter than 7 or longer than 8 characters or contains
219 illegal objID characters
222 raise ValueError(f
'objID longer than 8 characters: "{objID}"')
224 raise ValueError(f
'objID shorter than 7 characters: "{objID}"')
225 if any([ord(c) > 255
for c
in objID]):
226 raise ValueError(f
'{[c for c in objID if ord(c) > 255]} not legal objID characters (ascii [1, 255])')
228 ssObjectID = ord(objID[0])
229 for character
in objID[1:]:
231 ssObjectID += ord(character)
236 """Convert from Rubin ssObjectID to Minor Planet Center packed provisional
247 Minor Planet Center packed provisional designation.
252 if ssObjectID < 0
or ssObjectID >= (1 << 64):
253 raise ValueError(f
'ssObjectID ({ssObjectID}) outside [0, 2^64 - 1].')
255 objID =
''.join([chr((ssObjectID >> (8 * i)) % 256)
for i
in reversed(range(0, 8))])
256 objID = objID.replace(
'\x00',
'')
266 B612 code to pack a unpacked MPC designation. For example,
267 provisional designation 1998 SS162 will be packed to J98SG2S.
268 Permanent designation 323 will be packed to 00323.
270 TODO: add support for comet and natural satellite designations
275 MPC unpacked designation.
280 MPC packed form designation.
284 ValueError : If designation cannot be packed.
305 "Unpacked designation '{}' could not be packed.\n"
306 "It could not be recognized as any of the following:\n"
307 " - a numbered object (e.g. '3202', '203289', '3140113')\n"
308 " - a provisional designation (e.g. '1998 SV127', '2008 AA360')\n"
309 " - a survey designation (e.g. '2040 P-L', '3138 T-1')"
311 raise ValueError(err.format(designation))
314BASE62 =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
315BASE62_MAP = {BASE62[i]: i
for i
in range(len(BASE62))}
325 epoch_pf = str(epoch_pf)
326 year = int(epoch_pf[0], base=32) * 100 + int(epoch_pf[1:3])
327 month = int(epoch_pf[3], base=32)
328 day = int(epoch_pf[4], base=32)
329 isot_string =
"{:d}-{:02d}-{:02d}".format(year, month, day)
331 if len(epoch_pf) > 5:
332 fractional_day = float(
"." + epoch_pf[5:])
333 hours = int((24 * fractional_day))
334 minutes = int(60 * ((24 * fractional_day) - hours))
335 seconds = 3600 * (24 * fractional_day - hours - minutes / 60)
336 isot_string +=
"T{:02d}:{:02d}:{:09.6f}".format(hours, minutes, seconds)
338 return Time(isot_string, format=
"isot", scale=
"tt")
343 Convert MPC packed form dates (in the TT time scale) to
344 MJDs in TT. See: https://minorplanetcenter.net/iau/info/PackedDates.html
345 for details on the packed date format.
349 pf_tt : `~numpy.ndarray` (N)
350 MPC-style packed form epochs in the TT time scale.
354 mjd_tt : `~astropy.time.core.Time` (N)
366 Pack a numbered MPC designation.
368 Examples of numbered designations:
383 MPC numbered designation.
388 MPC packed numbered designation.
392 ValueError : If the numbered designation cannot be packed.
393 If the numbered designation is larger than 15396335.
395 number = int(designation)
396 if number > 15396335:
398 "Numbered designation is too large. Maximum supported is 15396335."
402 return "{:05}".format(number)
403 elif (number >= 100000)
and (number <= 619999):
404 bigpart, remainder = divmod(number, 10000)
405 return f
"{BASE62[bigpart]}{remainder:04}"
410 number_pf.append(BASE62[int(x % 62)])
414 return "~{}".format(
"".join(number_pf).zfill(4))
419 Pack a provisional MPC designation.
421 Examples of provisional designations:
436 MPC provisional designation.
441 MPC packed provisional designation.
445 ValueError : If the provisional designation cannot be packed.
446 The provisional designations is not at least 6 characters long.
447 The first 4 characters of the provisional designation are not a year.
448 The 5th character of the provisional designation is not a space.
449 The provisional designation contains a hyphen.
450 The half-month letter is I or Z.
452 if len(designation) < 6:
454 "Provisional designations should be at least 6 characters long."
456 if not designation[:3].isdecimal():
458 "Expected the first 4 characters of the provisional designation to be a year."
460 if designation[4] !=
" ":
462 "Expected the 5th character of the provisional designation to be a space."
464 if "-" in designation:
465 raise ValueError(
"Provisional designations cannot contain a hyphen.")
467 year = BASE62[int(designation[0:2])] + designation[2:4]
468 letter1 = designation[5]
469 letter2 = designation[6]
470 cycle = designation[7:]
472 if letter1
in {
"I",
"Z"}:
473 raise ValueError(
"Half-month letters cannot be I or Z.")
474 if letter1.isdecimal()
or letter2.isdecimal():
475 raise ValueError(
"Invalid provisional designation.")
479 cycle_int = int(cycle)
481 cycle_pf = str(cycle_int).zfill(2)
483 cycle_pf = BASE62[cycle_int // 10] + str(cycle_int % 10)
485 designation_pf =
"{}{}{}{}".format(year, letter1, cycle_pf, letter2)
486 return designation_pf
491 Pack a survey MPC designation.
493 Examples of survey designations:
503 MPC survey designation.
508 MPC packed survey designation.
512 ValueError : If the survey designation cannot be packed.
513 The survey designation does not start with P-L, T-1, T-2, or T-3.
515 number = designation[0:4]
516 survey = designation[5:]
521 elif survey[0:2] ==
"T-" and survey[2]
in {
"1",
"2",
"3"}:
522 survey_pf =
"T{}S".format(survey[2])
525 raise ValueError(
"Survey designations must start with P-L, T-1, T-2, T-3.")
527 designation_pf =
"{}{}".format(survey_pf, number.zfill(4))
528 return designation_pf
533 Unpack a numbered MPC designation.
535 Examples of numbered designations:
550 MPC packed numbered designation.
555 MPC unpacked numbered designation.
559 ValueError : If the numbered designation cannot be unpacked.
560 The packed numbered designation is not at least 4 characters long.
564 if designation_pf.isdecimal():
565 number = int(designation_pf)
568 elif designation_pf[0] ==
"~":
570 number_pf = designation_pf[1:]
571 for i, c
in enumerate(number_pf):
572 power = len(number_pf) - (i + 1)
573 number += BASE62_MAP[c] * (62**power)
577 number = BASE62_MAP[designation_pf[0]] * 10000 + int(designation_pf[1:])
580 raise ValueError(
"Packed numbered designation could not be unpacked.")
582 designation = str(number)
589 Unpack a provisional MPC designation.
591 Examples of provisional designations:
606 MPC packed provisional designation.
611 MPC unpacked provisional designation.
615 ValueError : If the provisional designation cannot be unpacked.
616 The packed provisional designation is not 7 characters long.
617 The packed provisional designation does not have a year.
619 if len(designation_pf) != 7:
620 raise ValueError(
"Provisional designation must be 7 characters long.")
621 if not designation_pf[1].isdecimal()
or not designation_pf[2].isdecimal():
622 raise ValueError(
"Provisional designation must have a year.")
623 year = str(BASE62_MAP[designation_pf[0]] * 100 + int(designation_pf[1:3]))
624 letter1 = designation_pf[3]
625 letter2 = designation_pf[6]
626 if letter1.isdecimal()
or letter2.isdecimal():
628 cycle1 = designation_pf[4]
629 cycle2 = designation_pf[5]
631 number = int(BASE62_MAP[cycle1]) * 10 + BASE62_MAP[cycle2]
635 number_str = str(number)
637 designation =
"{} {}{}{}".format(year, letter1, letter2, number_str)
644 Unpack a survey MPC designation.
646 Examples of survey designations:
656 MPC packed survey designation.
661 MPC unpacked survey designation.
665 ValueError : If the survey designation cannot be unpacked.
666 The packed survey designation does not start with PLS, T1S, T2S, or T3S.
668 number = int(designation_pf[3:8])
669 survey_pf = designation_pf[0:3]
670 if survey_pf
not in {
"PLS",
"T1S",
"T2S",
"T3S"}:
672 "Packed survey designation must start with PLS, T1S, T2S, or T3S."
675 if survey_pf ==
"PLS":
678 if survey_pf[0] ==
"T" and survey_pf[2] ==
"S":
679 survey =
"T-{}".format(survey_pf[1])
681 designation =
"{} {}".format(number, survey)
687 Unpack a packed MPC designation. For example, provisional
688 designation J98SG2S will be unpacked to 1998 SS162. Permanent
689 designation 00323 will be unpacked to 323.
691 TODO: add support for comet and natural satellite designations
696 MPC packed form designation.
701 MPC unpacked designation.
705 ValueError : If designation_pf cannot be unpacked.
727 "Packed form designation '{}' could not be unpacked.\n"
728 "It could not be recognized as any of the following:\n"
729 " - a numbered object (e.g. '03202', 'K3289', '~AZaz')\n"
730 " - a provisional designation (e.g. 'J98SC7V', 'K08Aa0A')\n"
731 " - a survey designation (e.g. 'PLS2040', 'T1S3138')"
733 raise ValueError(err.format(designation_pf))
obj_id_to_ss_object_id(objID)
ss_object_id_to_obj_id(ssObjectID)
str unpack_numbered_designation(str designation_pf)
str unpack_mpc_designation(str designation_pf)
str unpack_survey_designation(str designation_pf)
Time _unpack_mpc_date(str epoch_pf)
str unpack_provisional_designation(str designation_pf)
convert_spherical_array(array)
str pack_mpc_designation(str designation)
str pack_provisional_designation(str designation)
Time convert_mpc_packed_dates(npt.ArrayLike pf_tt)
convert_spherical(ra, dec)
query_disc(nside, ra, dec, max_rad, min_rad=0)
str pack_survey_designation(str designation)
str pack_numbered_designation(str designation)