|
1 | 1 | # Licensed under a 3-clause BSD style license - see LICENSE.rst
|
2 | 2 | """
|
3 | 3 | ======================
|
4 |
| -sbpy data.Ephem Module |
| 4 | +sbpy.data.ephem Module |
5 | 5 | ======================
|
6 | 6 |
|
7 |
| -Class for storing and querying ephemerides |
| 7 | +Class for storing and querying ephemerides. |
| 8 | +
|
| 9 | +Ephemerides may be generated by this module via command line: |
| 10 | +
|
| 11 | +:code: |
| 12 | + python3 -m sbpy.data.ephem |
| 13 | +
|
| 14 | +Or with the ``sbpy-ephem`` command line script. |
8 | 15 |
|
9 | 16 | created on June 04, 2017
|
| 17 | +
|
10 | 18 | """
|
| 19 | + |
11 | 20 | import os
|
| 21 | +import argparse |
12 | 22 | from warnings import warn
|
| 23 | +from typing import Union |
13 | 24 |
|
14 | 25 | import numpy as np
|
15 | 26 | from numpy import ndarray, hstack, iterable
|
@@ -525,7 +536,7 @@ def from_miriade(cls, targetids, objtype='asteroid',
|
525 | 536 | * For detailed explanations of the queried fields, refer to
|
526 | 537 | `astroquery.imcce.MiriadeClass.get_ephemerides` and the
|
527 | 538 | `Miriade documentation
|
528 |
| - <http://vo.imcce.fr/webservices/miriade/?documentation>`_. |
| 539 | + <https://vo.imcce.fr/webservices/miriade/?documentation>`_. |
529 | 540 | * By default, all properties are provided in the J2000.0 reference
|
530 | 541 | system. Different settings can be chosen using
|
531 | 542 | additional keyword arguments as used by
|
@@ -863,3 +874,211 @@ def from_oo(cls, orbit, epochs=None, location='500', scope='full',
|
863 | 874 | ephem.table.remove_column('MJD')
|
864 | 875 |
|
865 | 876 | return ephem
|
| 877 | + |
| 878 | + |
| 879 | +@requires("astroquery") |
| 880 | +def main(): |
| 881 | + """Command line script for ephemeris generation.""" |
| 882 | + |
| 883 | + from .names import Names, TargetNameParseError |
| 884 | + |
| 885 | + today: Time = Time(Time.now().iso[:10]) |
| 886 | + |
| 887 | + parser: argparse.ArgumentParser = argparse.ArgumentParser() |
| 888 | + parser.add_argument( |
| 889 | + "service", |
| 890 | + choices=("horizons", "miriade", "mpc"), |
| 891 | + help="online service to use for ephemeris", |
| 892 | + ) |
| 893 | + parser.add_argument( |
| 894 | + "target", |
| 895 | + ) |
| 896 | + parser.add_argument( |
| 897 | + "--location", |
| 898 | + "-l", |
| 899 | + default="500", |
| 900 | + help="observer location", |
| 901 | + ) |
| 902 | + parser.add_argument( |
| 903 | + "--start", |
| 904 | + default=today, |
| 905 | + type=Time, |
| 906 | + help="start time (UTC)", |
| 907 | + ) |
| 908 | + parser.add_argument( |
| 909 | + "--stop", default=today + 30 * u.day, type=Time, help="stop time (UTC)" |
| 910 | + ) |
| 911 | + step_mutex = parser.add_mutually_exclusive_group() |
| 912 | + step_mutex.add_argument( |
| 913 | + "--step", |
| 914 | + default="1 d", |
| 915 | + type=u.Quantity, |
| 916 | + help="ephemeris step size with units or number of steps", |
| 917 | + ) |
| 918 | + parser.add_argument( |
| 919 | + "--radec", |
| 920 | + "-r", |
| 921 | + default="hmsdms", |
| 922 | + choices=("hmsdms", "deg"), |
| 923 | + help="RA, Dec coordinate format", |
| 924 | + ) |
| 925 | + |
| 926 | + horizons: argparse._ArgumentGroup = parser.add_argument_group( |
| 927 | + "JPL Horizons options" |
| 928 | + ) |
| 929 | + horizons.add_argument( |
| 930 | + "--id-type", |
| 931 | + "-i", |
| 932 | + default=None, |
| 933 | + choices=( |
| 934 | + "smallbody", |
| 935 | + "designation", |
| 936 | + "name", |
| 937 | + "asteroid_name", |
| 938 | + "comet_name", |
| 939 | + ), |
| 940 | + help=( |
| 941 | + "target identifer type; automatically set to 'designation' for " |
| 942 | + "target names that appear to be a cometary designation" |
| 943 | + ), |
| 944 | + ) |
| 945 | + horizons.add_argument( |
| 946 | + "--quantities", |
| 947 | + "-q", |
| 948 | + default="1,3,9,19,20,23,24,27,33", |
| 949 | + help="table quantities to return as a comma-separated list of integers", |
| 950 | + ) |
| 951 | + |
| 952 | + miriade: argparse._ArgumentGroup = parser.add_argument_group( |
| 953 | + "IMCCE Miriade options" |
| 954 | + ) |
| 955 | + miriade.add_argument( |
| 956 | + "--type", |
| 957 | + "-t", |
| 958 | + default="asteroid", |
| 959 | + choices=( |
| 960 | + "asteroid", |
| 961 | + "comet", |
| 962 | + "dwarf planet", |
| 963 | + "planet", |
| 964 | + "satellite", |
| 965 | + ), |
| 966 | + help="target identifer type", |
| 967 | + ) |
| 968 | + |
| 969 | + args: argparse.Namespace = parser.parse_args() |
| 970 | + |
| 971 | + eph: Ephem |
| 972 | + epochs: dict = { |
| 973 | + "start": args.start, |
| 974 | + "stop": args.stop, |
| 975 | + } |
| 976 | + if args.service == "mpc": |
| 977 | + if args.step.unit == u.dimensionless_unscaled: |
| 978 | + epochs["number"] = int(args.step) |
| 979 | + else: |
| 980 | + epochs["step"] = args.step |
| 981 | + |
| 982 | + eph = Ephem.from_mpc( |
| 983 | + args.target, |
| 984 | + epochs=epochs, |
| 985 | + location=args.location, |
| 986 | + ) |
| 987 | + |
| 988 | + # simplify output |
| 989 | + for k in ["Targetname"]: |
| 990 | + del eph.table[k] |
| 991 | + elif args.service == "horizons": |
| 992 | + epochs["step"] = ( |
| 993 | + int(args.step) if args.step.unit == u.dimensionless_unscaled else args.step |
| 994 | + ) |
| 995 | + |
| 996 | + # comet specific options: always avoid multiple fragment matches, always |
| 997 | + # return closest apparition |
| 998 | + closest_apparition: bool = False |
| 999 | + no_fragments: bool = False |
| 1000 | + id_type: Union[str, None] = args.id_type |
| 1001 | + try: |
| 1002 | + Names.parse_comet(args.target) |
| 1003 | + closest_apparition = True |
| 1004 | + no_fragments = True |
| 1005 | + id_type = "designation" if id_type is None else id_type |
| 1006 | + except TargetNameParseError: |
| 1007 | + pass |
| 1008 | + |
| 1009 | + eph = Ephem.from_horizons( |
| 1010 | + args.target, |
| 1011 | + id_type=id_type, |
| 1012 | + closest_apparition=closest_apparition, |
| 1013 | + no_fragments=no_fragments, |
| 1014 | + epochs=epochs, |
| 1015 | + location=args.location, |
| 1016 | + quantities=args.quantities, |
| 1017 | + ) |
| 1018 | + |
| 1019 | + # simplify output |
| 1020 | + eph["epoch"].format = "iso" |
| 1021 | + eph["ra"] = eph["ra"].unmasked |
| 1022 | + eph["dec"] = eph["dec"].unmasked |
| 1023 | + for k in ["M1", "k1", "solar_presence", "lunar_presence", "targetname"]: |
| 1024 | + del eph.table[k] |
| 1025 | + elif args.service == "miriade": |
| 1026 | + if args.step.unit == u.dimensionless_unscaled: |
| 1027 | + epochs["number"] = int(args.step) |
| 1028 | + else: |
| 1029 | + epochs["step"] = args.step |
| 1030 | + |
| 1031 | + eph = Ephem.from_miriade( |
| 1032 | + args.target, |
| 1033 | + objtype=args.type, |
| 1034 | + epochs=epochs, |
| 1035 | + location=args.location, |
| 1036 | + coordtype=1, |
| 1037 | + ) |
| 1038 | + |
| 1039 | + # simplify output |
| 1040 | + eph["epoch"].format = "iso" |
| 1041 | + for k in ["target"]: |
| 1042 | + del eph.table[k] |
| 1043 | + for k in eph.field_names: |
| 1044 | + if hasattr(eph[k], "unmasked"): |
| 1045 | + eph[k] = eph[k].unmasked |
| 1046 | + |
| 1047 | + # convert RA and Dec to Angle in units of degree |
| 1048 | + eph["ra"] = Angle(eph["ra"], eph["ra"].unit).to("deg") |
| 1049 | + eph["dec"] = Angle(eph["dec"], eph["dec"].unit).to("deg") |
| 1050 | + |
| 1051 | + if args.radec == "hmsdms": |
| 1052 | + eph["ra"].info.format = lambda x: x.to_string( |
| 1053 | + sep=":", precision=2, unit="hourangle" |
| 1054 | + ) |
| 1055 | + eph["dec"].info.format = lambda x: x.to_string(sep=":", precision=1) |
| 1056 | + else: |
| 1057 | + eph["ra"].info.format = lambda x: x.to_string() |
| 1058 | + eph["dec"].info.format = lambda x: x.to_string() |
| 1059 | + |
| 1060 | + # unified output order for most common columns |
| 1061 | + fields = eph.field_names |
| 1062 | + for k in eph._translate_columns( |
| 1063 | + [ |
| 1064 | + "RA*cos(Dec)_rate", |
| 1065 | + "DEC_rate", |
| 1066 | + "elong", |
| 1067 | + "phase", |
| 1068 | + "delta", |
| 1069 | + "rh", |
| 1070 | + "dec", |
| 1071 | + "ra", |
| 1072 | + "epoch", |
| 1073 | + ], |
| 1074 | + ignore_missing=True, |
| 1075 | + ): |
| 1076 | + if k not in fields: |
| 1077 | + continue |
| 1078 | + fields.insert(0, fields.pop(fields.index(k))) |
| 1079 | + |
| 1080 | + eph[fields].table.pprint_all() |
| 1081 | + |
| 1082 | + |
| 1083 | +if __name__ == "__main__": |
| 1084 | + main() |
0 commit comments