13
13
from astropy .table import Table , Column
14
14
from astropy .io import ascii
15
15
from astropy .time import Time
16
+ from astropy import units as u
16
17
from astropy .utils .exceptions import AstropyDeprecationWarning
17
18
from astropy .utils .decorators import deprecated_renamed_argument , deprecated_attribute
18
19
@@ -53,14 +54,14 @@ def __init__(self, id=None, *, location=None, epochs=None,
53
54
54
55
id : str or dict, required
55
56
Name, number, or designation of target object. Uses the same codes
56
- as JPL Horizons. Arbitrary topocentric coordinates can be added
57
- in a dict. The dict has to be of the form
58
- { ``'lon '``: longitude in deg (East positive, West
59
- negative), ``'lat '``: latitude in deg (North positive, South
60
- negative), ``'elevation '``: elevation in km above the reference
61
- ellipsoid, [``' body'``: Horizons body ID of the central body;
62
- optional; if this value is not provided it is assumed that this
63
- location is on Earth]} .
57
+ as JPL Horizons. Arbitrary topocentric coordinates can be added in a
58
+ dict. The dict has to be of the form {``'lon'``: longitude in deg
59
+ (East positive, West negative), ``'lat '``: latitude in deg (North
60
+ positive, South negative), ``'elevation '``: elevation in km above
61
+ the reference ellipsoid, [ ``'body '``: Horizons body ID of the
62
+ central body; optional; if this value is not provided it is assumed
63
+ that this location is on Earth]}. Float values are assumed to have
64
+ units of degrees and kilometers .
64
65
65
66
location : str or dict, optional
66
67
Observer's location for ephemerides queries or center body name for
@@ -69,12 +70,13 @@ def __init__(self, id=None, *, location=None, epochs=None,
69
70
ephemerides queries and the Sun's center for elements and vectors
70
71
queries. Arbitrary topocentric coordinates for ephemerides queries
71
72
can be provided in the format of a dictionary. The dictionary has to
72
- be of the form {``'lon'``: longitude in deg (East positive, West
73
- negative), ``'lat'``: latitude in deg (North positive, South
74
- negative), ``'elevation'``: elevation in km above the reference
75
- ellipsoid, [``'body'``: Horizons body ID of the central body;
76
- optional; if this value is not provided it is assumed that this
77
- location is on Earth]}.
73
+ be of the form {``'lon'``: longitude (East positive, West negative),
74
+ ``'lat'``: latitude (North positive, South negative),
75
+ ``'elevation'``: elevation above the reference ellipsoid,
76
+ [``'body'``: Horizons body ID of the central body; optional; if this
77
+ value is not provided it is assumed that this location is on
78
+ Earth]}. Float values are assumed to have units of degrees and
79
+ kilometers.
78
80
79
81
epochs : scalar, list-like, or dictionary, optional
80
82
Either a list of epochs in JD or MJD format or a dictionary defining
@@ -117,16 +119,10 @@ def __init__(self, id=None, *, location=None, epochs=None,
117
119
"""
118
120
119
121
super ().__init__ ()
120
- # check & format coordinate dictionaries for id and location; simply
121
- # treat other values as given
122
- if isinstance (id , Mapping ):
123
- self .id = self ._prep_loc_dict (dict (id ), "id" )
124
- else :
125
- self .id = id
126
- if isinstance (location , Mapping ):
127
- self .location = self ._prep_loc_dict (dict (location ), "location" )
128
- else :
129
- self .location = location
122
+
123
+ self .id = id
124
+ self .location = location
125
+
130
126
# check for epochs to be dict or list-like; else: make it a list
131
127
if epochs is not None :
132
128
if isinstance (epochs , (list , tuple , ndarray )):
@@ -185,6 +181,32 @@ def __str__(self):
185
181
str (self .epochs ),
186
182
str (self .id_type ))
187
183
184
+ @property
185
+ def id (self ):
186
+ return self ._id
187
+
188
+ @id .setter
189
+ def id (self , _id ):
190
+ # check & format coordinate dictionaries for id; simply treat other
191
+ # values as given
192
+ if isinstance (_id , Mapping ):
193
+ self ._id = self ._prep_loc_dict (dict (_id ), "id" )
194
+ else :
195
+ self ._id = _id
196
+
197
+ @property
198
+ def location (self ):
199
+ return self ._location
200
+
201
+ @location .setter
202
+ def location (self , _location ):
203
+ # check & format coordinate dictionaries for location; simply treat
204
+ # other values as given
205
+ if isinstance (_location , Mapping ):
206
+ self ._location = self ._prep_loc_dict (dict (_location ), "location" )
207
+ else :
208
+ self ._location = _location
209
+
188
210
# ---------------------------------- query functions
189
211
190
212
@deprecated_renamed_argument ("get_raw_response" , None , since = "0.4.7" ,
@@ -593,10 +615,7 @@ def ephemerides_async(self, *, airmass_lessthan=99,
593
615
if self .id is None :
594
616
raise ValueError ("'id' parameter not set. Query aborted." )
595
617
elif isinstance (self .id , dict ):
596
- commandline = (
597
- f"g:{ self .id ['lon' ]} ,{ self .id ['lat' ]} ,"
598
- f"{ self .id ['elevation' ]} @{ self .id ['body' ]} "
599
- )
618
+ commandline = self ._format_id_coords (self .id )
600
619
else :
601
620
commandline = str (self .id )
602
621
if self .location is None :
@@ -831,16 +850,20 @@ def elements_async(self, *, get_query_payload=False,
831
850
832
851
URL = conf .horizons_server
833
852
834
- # check for required information
853
+ # check for required information and assemble commandline stub
835
854
if self .id is None :
836
855
raise ValueError ("'id' parameter not set. Query aborted." )
856
+ elif isinstance (self .id , dict ):
857
+ commandline = self ._format_id_coords (self .id )
858
+ else :
859
+ commandline = str (self .id )
860
+
837
861
if self .location is None :
838
862
self .location = '500@10'
839
863
if self .epochs is None :
840
864
self .epochs = Time .now ().jd
841
865
842
- # assemble commandline based on self.id_type
843
- commandline = str (self .id )
866
+ # expand commandline based on self.id_type
844
867
if self .id_type in ['designation' , 'name' ,
845
868
'asteroid_name' , 'comet_name' ]:
846
869
commandline = ({'designation' : 'DES=' ,
@@ -859,7 +882,7 @@ def elements_async(self, *, get_query_payload=False,
859
882
commandline += ' NOFRAG;'
860
883
861
884
if isinstance (self .location , dict ):
862
- raise ValueError (('cannot use topographic position in orbital'
885
+ raise ValueError (('cannot use topographic position in orbital '
863
886
'elements query' ))
864
887
865
888
# configure request_payload for ephemerides query
@@ -1080,7 +1103,7 @@ def vectors_async(self, *, get_query_payload=False,
1080
1103
if self .id is None :
1081
1104
raise ValueError ("'id' parameter not set. Query aborted." )
1082
1105
elif isinstance (self .id , dict ):
1083
- commandline = "g:{lon},{lat},{elevation}@{body}" . format ( ** self .id )
1106
+ commandline = self . _format_id_coords ( self .id )
1084
1107
else :
1085
1108
commandline = str (self .id )
1086
1109
if self .location is None :
@@ -1183,20 +1206,38 @@ def _prep_loc_dict(loc_dict, attr_name):
1183
1206
)
1184
1207
if 'body' not in loc_dict :
1185
1208
loc_dict ['body' ] = 399
1209
+ # assumed units are degrees and km
1210
+ loc_dict ["lat" ] = u .Quantity (loc_dict ["lat" ], u .deg )
1211
+ loc_dict ["lon" ] = u .Quantity (loc_dict ["lon" ], u .deg )
1212
+ loc_dict ["elevation" ] = u .Quantity (loc_dict ["elevation" ], u .km )
1186
1213
return loc_dict
1187
1214
1188
1215
@staticmethod
1189
1216
def _location_to_params (loc_dict ):
1190
- """translate a 'location' dict to a dict of request parameters"""
1191
- loc_dict = {
1217
+ """translate a 'location' dict to request parameters"""
1218
+
1219
+ location = {
1192
1220
"CENTER" : f"coord@{ loc_dict ['body' ]} " ,
1193
1221
"COORD_TYPE" : "GEODETIC" ,
1194
- "SITE_COORD" : "," .join (
1195
- str (float (loc_dict [k ])) for k in ['lon' , 'lat' , 'elevation' ]
1196
- )
1222
+ "SITE_COORD" : "'{}'" .format (str (HorizonsClass ._format_site_coords (loc_dict )))
1197
1223
}
1198
- loc_dict ["SITE_COORD" ] = f"'{ loc_dict ['SITE_COORD' ]} '"
1199
- return loc_dict
1224
+ return location
1225
+
1226
+ @staticmethod
1227
+ def _format_coords (coords ):
1228
+ """Dictionary to Horizons API formatted lon/lat/elevation coordinate triplet."""
1229
+ return (f"{ coords ['lon' ].to_value ('deg' )} ,{ coords ['lat' ].to_value ('deg' )} ,"
1230
+ f"{ coords ['elevation' ].to_value ('km' )} " )
1231
+
1232
+ @staticmethod
1233
+ def _format_site_coords (coords ):
1234
+ """`location` dictionary to SITE_COORDS parameter."""
1235
+ return HorizonsClass ._format_coords (coords )
1236
+
1237
+ @staticmethod
1238
+ def _format_id_coords (coords ):
1239
+ """`id` dictionary to COMMAND parameter's coordinate format."""
1240
+ return f"g:{ HorizonsClass ._format_coords (coords )} @{ coords ['body' ]} "
1200
1241
1201
1242
def _parse_result (self , response , verbose = None ):
1202
1243
"""
0 commit comments