From ae008dc55ef618546e5bea5defc4b7cf5c05905e Mon Sep 17 00:00:00 2001 From: Antonio Hidalgo Date: Wed, 27 Feb 2019 20:59:00 +0530 Subject: [PATCH 01/16] Add dastcom module --- sbpy/dastcom5/README.txt | 1227 +++++++++++++++++++++++++++++++++++++ sbpy/dastcom5/__init__.py | 13 + sbpy/dastcom5/dastcom5.py | 590 ++++++++++++++++++ 3 files changed, 1830 insertions(+) create mode 100644 sbpy/dastcom5/README.txt create mode 100644 sbpy/dastcom5/__init__.py create mode 100644 sbpy/dastcom5/dastcom5.py diff --git a/sbpy/dastcom5/README.txt b/sbpy/dastcom5/README.txt new file mode 100644 index 000000000..c8a159de8 --- /dev/null +++ b/sbpy/dastcom5/README.txt @@ -0,0 +1,1227 @@ +2014-Aug-18 DASTCOM5 + USER QUICK START + + CONTENTS + + BACKGROUND + + DISTRIBUTION RETRIEVAL + + USAGE + Building software and library + Running DXLOOK + Using the FORTRAN reader library + Example 1: Open DASTCOM5, return all information in a record + Example 2: Open DASTCOM5, return only DASTCOM3 information + Example 3: Open DASTCOM5, return only DASTCOM3 data in legacy D3READ order + Example 4: Open legacy DASTCOM3, return data in legacy D3READ order + + PROGRAMMER NOTES + Overview of database structure + DAST5 + DCOM5 + ADDRESSING + SCANNING THE DATABASE + INDEX FILE + Alternative access methods + + CONTENTS OF DASTCOM5 + + DASTCOM5 BYTE MAP + + CONTACT + + +BACKGROUND + + DASTCOM5 is a direct-access binary database. It contains heliocentric + ecliptic osculating elements for the known asteroids and comets, at single + instants, determined by a least-squares orbit solution fit to optical and + radar astrometric measurements. + + Additional physical, dynamical, and covariance parameters are included when + known. A total of 142 parameters per object are defined within DASTCOM5 + though many may not yet be assigned values, being undetermined. See the + "./dastcom5/src/curdef.inc" file for detailed information on the defined + fields, after retrieving and unzipping the distribution file described below. + + This information is suitable for initializing numerical integrators, assessing + orbit geometry, computing trajectory uncertainties, visual magnitude and, to + some extent, summarizing physical characterization of the body. It is the + database used by the JPL Horizons ephemeris system. + + Each asteroid has one data record containing the most recent information for + that object. Comets, however, may have multiple records, reflecting solutions + at different apparitions. This is because acceleration due to non-gravitational + out-gassing can vary during different perihelion passages and be discernable + from the measurement data. Unless doing historical research, the record for + a comets' apparition closest to the present is typically most relevant. + + DASTCOM5 is a portable, subset product exported from a larger MySQL-based + relational master database called SBDB ("Small-Body Database") maintained at + the NASA/Jet Propulsion Laboratory. + + The DASTCOM5 distribution file archive is updated when necessary to include + newly discovered objects or orbit solution updates derived from newly reported + measurements. Database updates typically occur a couple times per day, but + potentially as frequently as once per hour. They are placed on the public + FTP site of JPL's Solar System Dynamics Group (below). + + The DASTCOM5 distribution .zip file archive contains the following: + + * two binary database files (one holding asteroid data, the second holding + comet data), + + * a plain-text index (linking all objects to their DASTCOM5 record, + permitting look-up based on name, designation, SPK ID, packed MPC + designation, and historical aliases), + + * documentation, + + * latest database reader source code (FORTRAN). The software has been + tested using GFORTRAN (gfortran), Lahey (lf95), Intel (ifort), and + SunStudio (f95) compilers in both 32 and 64-bit builds, under RedHat + Linux 4/5/6. + + The legacy DASTCOM3 file, in use over the last 20+ years (without an official + reader routine), will continue to be produced by conversion indefinately, + using DASTCOM5 as a source and discarding and reorganizing data into the + old structure. + + However, DASTCOM3 cannot contain more than 999,999 object records and so + cannot be produced after that number of objects are cataloged. At the time of + this writing, there are ~624,000 small-body records. While it is likely + discoveries won't approach the DASTCOM3 limit for more than three years, it + is recommended users switch to DASTCOM5 well before that time. Note that + DASTCOM3 does not provide enough information to properly initialize modern + trajectory propagations for some objects having non-gravitational dynamics + (primarily comets with A3 parameters), and has therefore been obsolete for + that purpose for several years. + + DASTCOM4 was an extension to DASTCOM3, defined in 2001, and primarily used + internally at JPL. + + The outline below assumes UNIX/Linux/Mac command line functionality, but + should be adaptable to PC/Windows environments. + + +DISTRIBUTION RETRIEVAL: + + 1. Retrieve the latest database distribution by anonymous FTP from the + JPL Solar System Dynamics server: + + From command-line + + wget ftp://ssd.jpl.nasa.gov/pub/xfr/dastcom5.zip + + OR browser URL bar + + ftp://ssd.jpl.nasa.gov/pub/xfr/dastcom5.zip + + OR command-line FTP login + + ftp ssd.jpl.nasa.gov + Name: anonymous + Password: {your email address} + cd pub/xfr + binary + get dastcom5.zip + exit + + IMPORTANT NOTE: + The database could be updated at any moment within the interval 30-32 + minutes after any hour. Make sure your retrieval is not occurring during + this time to avoid creating a local database on your system potentially + corrupted due to the remote source file being almost instantly rewritten + with an update while your slower Internet transfer is in progress. + + 2. Unzip the archived directory structure + + unzip -ao dastcom5.zip + + The "-ao" options instruct unzip to convert text files to local forms + and over-write any existing files of the same name. + + A directory called "dastcom5" will be created in the current working + directory, along with five sub-directories: + + ./dastcom5/dat + /dast5_le.dat (binary asteroid data) + /dcom5_le.dat (binary comet data) + /dastcom.idx (plain-text database index) + /doc + /README.txt + /news.txt + /dastcom5.map + /src (FORTRAN source for libraries & apps) + /*.f + /*.inc + /Makefile + /dxlook.inp + /exe (initially empty) + /lib (initially empty) + + The /dat sub-directory contains the latest matched-set of databases. + + The database files can be moved and renamed, but the rest of this + discussion assumes the directory structure above for the purpose of + example. + + Note that the three database files in a distribution make up a "matched + set" and MUST be replaced/updated together. If an old 'dast5' is used with + a more recent 'dcom5' (or index), errors may result, including retrieval + of a different object than expected. + + Changes to the distribution or other developments will be noted in the + file './dastcom5/doc/news.txt' + +USAGE + + It is recommended the reader library and applications in the './dastcom5/src' + directory be used to read the database. Advantages include: + + - Binary-independent readability across IEEE platforms. It is not necessary + to have a version of the DASTCOM database that is binary-compatible with + your computer; the reader software translates as necessary. + + - Legacy database compatibility; transparently supports prior DASTCOM3 and + DASTCOM4 databases, and the old limited-release D3READ reader subroutine, + simplifying transition to the new database. + + - Transparent updates: if DASTCOM5 is altered in the future to include + additional information, user software need only be relinked with the + latest libraries from the distribution to read the new database + structure. Calling arguments and user software won't need to change -- + unless the user wants to use the new information. + + - Automatic management of asteroid & comet databases ... software merge of + the two database components is managed in the readers such that both can + be simultaneously and transparently accessed. + + - Error checking + + Since the reader software is configurable with respect to what data it returns, + it should be possible to duplicate the output of legacy readers users may have + for DASTCOM3, reducing the required changes in user code and more rapidly + eliminating the need for DASTCOM3. + + If the provided subroutines are not compatible with user application code, the + provided "dxlook" tool might be used to retrieve data in a shell or scripted + environment. Relevant details are also provided later for implementation of a + reader in other languages. The structure of the database records is summarized + in the text file './dastcom5/doc/dastcom5.map'. + + + Building Software and Library + ----------------------------- + + To build the 'dxlook' command-line application, and the library 'libdxread.a' + used to link with user application software, move to the source directory, + edit the Makefile to set the desired compiler and link flags, then execute a + "make all" command. On a Unix/Linux/Mac platform: + + 1. cd dastcom5/src + + 2. vi Makefile + + - The 'LIBDXREAD' and 'EXEDXREAD' variables can be altered to point to + a different destination for the library archive and executables, if + desired. + + - 'BITDXREAD' can be altered as necesary to select which memory model + (32 or 64-bit) is required for compatibility with user applications. + Options are '-m32' or '-m64' + + - Example settings for four FORTRAN compilers are shown (FC and FFLAGS + variables). It may be possible to simply alter comment-markers to + select the desired compiler. If not, create new FC and FFLAGS as + needed. + + - Once Makefile is customized for the local system, it can be renamed + 'makefile' (lower-case). This will prevent it from being + over-written during future releases while giving local changes + execution precedence over the default distribution 'Makefile' + (upper-case). However, keep an eye on "news.txt" in case an + additional program or subroutine is added to the distribution, and + the distribution Makefile is changed to include it. + + 3. make all + + This will build 'libdxread.a', created as '../lib/libdxread.a' + + Application program 'dxlook' will be created as '../exe/dxlook', + along with some other example programs in the same directory + + User applications would then link with 'libdxread.a' after + compilation to gain access to the database subroutines. + + The library and executable files can be relocated and renamed, though the rest + of this discussion assumes the above basic directory structure for the purpose + of example. + + + Running dxlook + -------------- + + 'dxlook' is a stand-alone command-line tool to rapidly examine DASTCOM + database records. It can also be used to examine legacy databases such as + DASTCOM3 and DASTCOM4. + + Type '../exe/dxlook' from the command-line to execute the program, assuming + the users' working directory location of './dastcom5/src' is unchanged. + + Type 'help' at the 'dxlook>' prompt to list commands. + + To view small-body data, enter a record number or, if the Unix/Linux/Mac + egrep utility is in your path, an asteroid name or designation. + + Type 'x' to exit the 'dxlook' program. + + Program directives are: + + Directive Meaning + ------------------ ----------------------------------------------------- + DB [path/file] Open specified database(s); DASTCOM 3-5 are supported + SUMM Summarize currently opened databases + INDEX [path/file] Specify optional ASCII index file for look-ups + FIELDS [list] Set field codes to display (default= -5, all DASTCOM5) + PAGER {path} Toggle output pager w/executable path (default= none) + LABEL [ON/OFF] Toggle display of field labels (default= ON) + HELP Display this list of directives (same as "?") + {Object} Display {object}; record #, name, designation, SPK ID + !{X} Pass {X} to operating system as a command + X Exit program; same as CLOSE, QUIT, EXIT + + 'dxlook' is controlled by an input file, keyboard, or combination of the two. + + It is recommended that set-up information which doesn't change, such as the + paths to the latest database files, be placed in an input file called + "./dxlook.inp". + + When 'dxlook' is run, it will first look for a file called 'dxlook.inp' in + the run-time directory, load anything there if found, then drop into keyboard + input, which would typically be specific user-queries of the database. + + This is what happened during the test above, using an example directive file + in the current working 'src' directory, './dastcom5/src/dxlook.inp' + + Create another customized dxlook directive file './dxlook.inp' in the + original top-level unzip directory ('cd ../..') containing the lines between + the '---' marks: + + --- + DB ./dastcom5/dat/dast5_le.dat + DB ./dastcom5/dat/dcom5_le.dat + INDEX ./dastcom5/dat/dastcom.idx + PAGER /bin/usr/less + --- + + "PAGER" can be set as needed to point to a preferred text paging program on + the local system. + + Now execute './dastcom5/exe/dxlook'. Type 'summ' at the prompt to summarize + the databases now open. Type "1" to look-up the object in record #1, "99942" + for the object in record 99942, and so on. + + While the default behavior is to display all defined DASTCOM fields, the + FIELDS directive can be used to request 'dxlook' display only select data. + For example, the directive ... + + FIELDS 14,11,802,807,808,809,804,805,806 + + ... requests display of only object name (14), designation (11), calendar + epoch (802), and orbital elements EC, A, QR, W, OM, IN. + + See the './dastcom5/src/curdef.inc' file for a list of all available fields + and their numeric codes. + + Some macros are also defined: + + 'FIELDS -3' requests legacy DASTCOM3 fields only, + 'FIELDS -4' requests legacy DASTCOM4 fields only, + 'FIELDS -5' restores the default, which is "all DASTCOM5 fields" + + Note that numeric data is always displayed first, followed by character data, + regardless of the order you specify with FIELDS. However, the order specified + within those two categories (numeric and character) is maintained for display. + + If the Unix/Linux/Mac 'egrep' command is in your path (type '!which egrep' in + 'dxlook' to determine if it can be found), and INDEX is defined, it will be + possible to look up objects based on their names, SPK IDs, designations, and + other aliases, including regular expressions. + + If there are multiple matches from such a search, select the desired object + using the unique DASTCOM record number on the left-most part of each index + line in the list of matches. + + If 'egrep' is not available in your path, only record numbers may be used + to do look-ups. + + + Using the FORTRAN Reader Library + -------------------------------- + + The principle behind usage of the reader library is to provide a list of data + to be retrieved during future calls to the reader. Each field in an asteroid or + comet record has a code number, as shown in file './dastcom5/src/curdef.inc'. + + The code for each desired field should be placed in an array in the order in + which they are to be returned. This output-request 'map' is then consulted for + each database read and used to determine what information is to be returned + from the read, and in what order. + + There are two primary subroutine calls for programmatic users, DXINI and + DXREAD, with several other special-purpose utility routines. + + DXINI initializes the reader package; the user specifies the database files + to use and the list of desired information and order in which to return it. + + DXREAD then retrieves one small-body data record, returning the requested + data in the specified order from the set-up call previously made to DXINI. + + See './dastcom5/src/dxread.f' comments for a list of all subroutines, details + of their calling arguments and specific discussion of how to use them. + + Some macro field codes ("-3","-4","-5") are available that emulate the return + of the old D3READ subroutine for DASTCOM3 and DASTCOM4. They can be used if + necessary for a "quick and dirty" inclusion of DASTCOM5, by those previously + using D3READ and wanting to minimize changes to their existing software, but + are not recommmended for general use. + + The obsolete D3READ subroutine they emulate returned different data in the + same array slots depending on whether the object was a comet or asteroid. + + If upgrading to DASTCOM5, it would be better to develop a list of every piece + of information needed for both comets and asteroids and put them in the + request list. The information will therefore be returned in the same position + whether the record is for an asteroid or a comet. Fields not defined for a + particular type of object will be returned as zero or blank, but the position + of the data won't change using this approach. + + The following are only four general examples, most relevant to legacy DASTCOM3 + users transitioning to DASTCOM5. Once the basic framework is in place + (example #1), minor variations allow adapting to a variety of other purposes + (examples #2-4). + + Example 1: Open DASTCOM5 and return all information in record (nominal case) + --------- +C +C** Parameterize array dimensions for convenience. Might instead use +C "INCLUDE dxparms.inc" and package NUMNS and NUMCH parameters for +C better future-proofing +C + INTEGER NUMNS0, NUMCH0 + PARAMETER( NUMNS0= 142) ! Max.# of numeric fields to be retrieved + PARAMETER( NUMCH0= 14) ! Max.# of character fields to be retrieved +C +C** Declare necessary variables for DXINI + CHARACTER*1 DBNAM(2)*256 + INTEGER IR8ORD(NUMNS0), ICHORD(NUMCH0), NR8, NCH, ISTAT + LOGICAL BUF, WARN +C +C** Declare necessary variables for DXREAD + CHARACTER*1 CHOUT5(NUMCH0)*80, CHOUT3*217, CERRMS*340 + INTEGER IOBJ, IZONE, LSRC, LERR + REAL*8 R8OUT(NUMNS0) +C +C** Declare local variables + INTEGER I +C +C** Initialization settings + DATA DBNAM / + & './dastcom5/dat/dast5_le.dat', ! Database #1 + & './dastcom5/dat/dcom5_le.dat' / ! Database #2 + DATA IR8ORD / -5,141*0 / ! Macro specifying all DASTCOM5 fields + DATA ICHORD / 14*0 / ! Requested character fields + DATA NR8,NCH / 142, 14 / ! Max. # of num. & char. fields to get + DATA BUF,WARN / .F., .F. / ! Normal values +C +C** Initialize DASTCOM reader package + CALL DXINI( DBNAM, IR8ORD, NR8, ICHORD, NCH, BUF, WARN, ISTAT ) +C +C** Check initialization return status + IF ( ISTAT .NE. 0 ) THEN + PRINT *,'Error on DXINI, ISTAT= ', ISTAT + CALL DXERR( CERRMS, LERR ) + PRINT *,CERRMS(1:LERR) + STOP + ELSE + PRINT *,'Nominal initialization' + END IF + +C** Set IOBJ for the desired objects' logical record & retrieve data + IOBJ= 4 ! Numbered asteroid Vesta + CALL DXREAD( IOBJ, IZONE, LSRC, R8OUT, CHOUT5, ISTAT ) +C +C** Check return status and display data + IF ( ISTAT .NE. 0 ) THEN + PRINT *,'Error on DXREAD(), ISTAT= ', ISTAT + CALL DXERR( CERRMS, LERR ) + PRINT *,CERRMS(1:LERR) + STOP + ELSE + PRINT *,'IZONE= ',IZONE ! Database zone of logical record IOBJ + PRINT *,'LSRC = ',LSRC ! Length of SRC vector + DO I= 1, NR8 ! Objects' numeric data, ordered by IR8ORD() + PRINT *,' R8OUT(',I,')= ',R8OUT(I) + END DO + IF ( NCH .GT. 1 ) THEN ! DASTCOM5 character array + DO I= 1, NCH ! Objects' character data, order by ICHORD() + PRINT *,' CHOUT5(',I,')= ',CHOUT5(I) + END DO + ELSE + PRINT *,' CHOUT3= ',CHOUT3 ! Legacy character block + END IF + END IF + + Depending on how elaborate user software for accessing DASTCOM is, users may + want to formally INCLUDE ./dastcom5/src/dxparms.inc in application programs + that use DXREAD(), and use the parameterized NUMNS and NUMCH values to enhance + compatibility with any future release. + + However, if the application will only ever use DASTCOM in one way, and + will not be concerned with future data that may or may not be added, this + generalization is not necessary. Further, if only a limited number of + fields are of interest, smaller dimensions can be specified, as per DXREAD + and DXINI documentation. + + + Example 2: Open DASTCOM5, return only DASTCOM3 [asteroid] information (subset) + --------- + + Replace three corresponding lines in nominal example #1 above with: + + DATA IR8ORD / ! Request DASTCOM3 asteroid num. fields + & 201,801,802,803,804,805,806,807,808,810, + & 811,809,432,433,401,402,439,431,438, 123*0 / + DATA ICHORD / ! Request DASTCOM3 asteroid char fields + & 14,1,13,11,4,6,7,8,3,5*0 / + DATA NR8,NCH / 19, 9 / ! Max. # num. & char. fields to get + + To generalize and support potential cometary data return for this case, one + could define alternate IR8ORD and ICHORD arrays for DASTCOM3 comet records, + then test whether object is comet or asteroid and re-initialize with DXCLOS + and DXINI calls to use the type-specific list. + + Even better (2b): define a single list that includes all DASTCOM3 asteroid and + comet fields. This avoids having to test what the object is and reinitialize + with a new list. + + DATA IR8ORD / ! Request DASTCOM3 ast+com num. fields + & 201,801,802,803,804,805,806,807,808,810, + & 811,809,432,433, + & 401,402,439,431,438, ! asteroid unique data + & 408,409,403,404,151,118*0/ ! stick comet-unique data at end + DATA ICHORD / ! Request DASTCOM3 ast+com char fields + & 14,1,13,11,4,6,7,8,3, + & 9,10, 2*0 / ! stick comet unique data at end + DATA NR8,NCH / 24, 11 / ! Max. # num. & char. fields to get + + + + Example 3: Open DASTCOM5, return only DASTCOM3 data in legacy D3READ order + --------- + + Replace three corresponding lines in nominal example #1 above with: + + DATA IR8ORD / -3,141*0 / ! Macro specifying only DASTCOM3 fields + . + DATA NR8,NCH / 18, 1 / ! Max. # num. & char. fields to get + . + CALL DXREAD( IOBJ, IZONE, LSRC, R8OUT, CHOUT3, ISTAT ) + + + + Example 4: Open legacy DASTCOM3, return data in legacy subroutine D3READ order + --------- + + Replace corresponding lines in nominal example #1 above with: + + DATA DBNAM / + & '/home/user/data/DASTCOM3' !Legacy database (change pointer) + & ' ' / + DATA IR8ORD / -3,141*0 / ! Macro specifying only DASTCOM3 fields + . + DATA NR8,NCH / 18, 1 / ! Max. # num. & char. fields to get + . + CALL DXREAD( IOBJ, IZONE, LSRC, R8OUT, CHOUT3, ISTAT ) + + +PROGRAMMER NOTES + + Overview of Database Structure + ------------------------------ + + Unlike legacy DASTCOM3 and DASTCOM4 databases, DASTCOM5 is provided as two + files; "dast5" contains numbered and unnumbered asteroids, while "dcom5" + contains comet records. + + Division into two files for asteroids and comets is done because the two types + of bodies contain different information. Comet records are fewer but contain + more potential data fields and so are individually larger than the much more + numerous asteroid records. + + Since a direct access file has one fixed record size, it is advantageous to use + two separate files for asteroids and comets, each with a different fixed record + size mediated in software. This avoids having total physical database size + driven by the few comets with larger records and reduces empty storage space as + the number of cataloged asteroids having records smaller than comets grows. + + As a result, while the total physical size of DASTCOM5 is about twice that of + DASTCOM3, it can store about seven times as much data. + + Both files contain a header record as physical record #1. These header + records include structural information that permits finding objects within + the file. + + + DAST5 + ----- + + 'dast5' contains two groups of objects: all the numbered asteroids followed + by all the unnumbered asteroids. + + 'Numbered asteroids' are those sequentially assigned a number by the IAU + Minor Planet Center, as measurements accumulate and knowledge of their orbit + becomes robust. + + 'Unnumbered asteroids' have less well-determined orbits, and are typically + more recently discovered. Once enough information is available for an + unnumbered asteroid to secure its orbit solution, it is numbered, and + relocated in the database to the numbered zone. + + Consequently, only numbered asteroid record numbers are fixed. All other + record numbers can shift as objects are moved around the database, thus the + need for an index to support look-ups. + + Record "byte" maps showing the specific content of header, asteroid, and comet + records are in the file './dastcom5/doc/dastcom5.map'. + + The 'dast5' file overall structure map is shown below, where BIAS() is as + returned by a call to DXBND: + + physical logical + record ---------------------- record + 1 Header (record #1) + ---------------------- --------------------_ + 1-BIAS(1) Numbered asteroid 1 1 | + 2-BIAS(1) Numbered asteroid 2 2 | + . | Zone 1 + . | (numbered ast.) + N-BIAS(1) Numbered asteroid N N _| + . _ + N-BIAS(1)+1 Unnumbered asteroid #1 N-BIAS(1)+1+BIAS(2) | + N-BIAS(1)+2 Unnumbered asteroid #2 N-BIAS(1)+2+BIAS(2) | + . | Zone 2 + . | (unnumbered ast.) + N-BIAS(1)+X Unnumbered asteroid #X N-BIAS(1)+X+BIAS(2) _| + + + DCOM5 + ----- + + The 'dcom5' overall file structure map is simpler and looks like this: + + physical logical + record ---------------------- record + 1 Header (record #1) + ---------------------- --------------------_ + 2 Comet record #1 2+BIAS(3) | + 3 Comet record #2 3+BIAS(3) | + . | Zone 3 (comets) + . | + Y+1 Comet record #Y Y+1+BIAS(3) _| + + + ADDRESSING + ---------- + + Considering the level of database flux, with objects being added and moved + around daily, the databases and DXREAD library package are organized to use + "logical record" addressing to look up objects. This offers some flexibility. + + The relationship between physical database record numbers and the logical + record numbers users pass to DXREAD to retrieve those records is ... + + physical_record = logical_record - bias_for_zone + + The bias pointer for each zone is given in the header, while the index file + provides each objects' logical record number. The above relationship then + permits calculation of the object's physical record, which can then be + directly read. + + This makes it possible for users to request IAU numbered object 1 (Ceres), for + example, by simply passing IOBJ= 1 to DXREAD(), even though the data is not + physically located in record 1. The reader software can relate that input to + the physical database given the structural information in the header. + + For unnumbered asteroids and comets, the logical address approach allows data + to be relocated as necessary for database maintenance while reducing the + apparent movement of records visible to users. + + + SCANNING THE DATABASE + --------------------- + + Header records also report the logical record boundaries for the categories of + objects. This information can be used, for example, to perform a sequential + search of the entire database as follows: + + Call DXINI to initialize, then call DXBND to retrieve the logical record + bounds (and bias pointers) for each category of object. Proceed to read each + record in sequence, calling DXREAD as IOBJ is incremented positively from + BND(4) to BND(1) for numbered asterods, BND(5) to BND(2) for unnumbered + asteroids, and from BND(6) to BND(3) for comets. + + + INDEX FILE + ---------- + + The index file './dastcom5/dat/dastcom.idx' is part of the "matched set" of + databases and corresponds to the 'dast5' and 'dcom5' of the same distribution + archive. The index is also valid for a legacy DASTCOM3 or DASTCOM4 database + corresponding to the same DASTCOM5 files. + + The index is a plain-text ASCII file suitable for pattern matching using one + of the 'grep' family of tools under Unix/Linux/Mac. + + An example index entry line (between the '----' markers): + +---- +751439 2013 LT14 ,3640966,2013 LT14,2010 NY13,3536865,K13L14T, +---- + + From left to right: + + 1: DASTCOM logical record number -- the value to pass to DXREAD() as IOBJ + (potentially up to an 8 digit integer, for DASTCOM5) + + 2: Space + + 3: Name followed by a comma (alternatively, primary designation, if not named) + + 4: Primary SPK ID number followed by a comma + + 5: Primary designation followed by a comma + + 6: Variable length list of historical or alternate designations + and SPK IDs (from when it was an unnumbered asteroid, for example) + + 7: Final item on the line is an MPC packed designation + + If developing a parsing routine for the index, robustness requires keeping + the length of each item flexible and using the space or comma delimiters as + bounds. In the future, names may grow longer, record and SPK-ID range may + change, etc. + + + Alternative Access Methods + -------------------------- + + It is strongly recommended the provided readers be used. However, if this is + not possible due to a particular language requirement or production + environment ... + + 1. Note that 'dxlook' (perhaps with directive "LABELS off") could be used in + an interpreted script or shell environment to do the database interaction, + with the output being loaded into script variables. + + 2. The databases themselves are not FORTRAN specific, but can be read using + any language that can load a byte-pattern into a properly typed variable + (Perl, etc.). Consult the byte map in './dastcom5/doc/dastcom5.map' to + determine the size and arrangement of each variable in header, asteroid, + and comet records, and have at it. Comments in the FORTRAN code may help. + + The database records consist of 1-byte, 2-byte, and 4-byte integers, + 4-byte and 8-byte floating point reals, and character data-types + (1-byte sequences). + + The nominal distribution files 'dast5_le.dat' and 'dcom5_le.dat' are + little-endian. Therefore, for multi-byte patterns, the first byte is + smallest. + + The provided readers automatically translate on big-endian systems, but + this would have to be handled by user-developed readers on big-endian + systems. However, some of those architectures (generally RISC-based) or + compilers (Intel FORTRAN, for example) may offer switchable endianness. + + +CONTENTS OF DASTCOM5 + + The following is excerpted from '../src/curdef.inc', which will always be +the definitive listing: + +C CURDEF.INC (FORTRAN) +C Add definitions to end of lists here if the database is altered to include +C additional parameters, but do not change or delete existing assignments. +C +C Data-fields currently defined and retrievable by calling DXREAD are listed +C below. Not all retrievable fields will be populated with data. +C +C Column "CODE" gives the integer used to request that quantity by its placement +C in the IR8ORD() array passed to DXINI. The requested value will be stored in +C the corresponding position of the R8OUT output array returned by DXREAD. +C +C All numeric data is returned to the user by DXREAD as 8-byte IEEE floating +C point, although the numeric data is physically stored in the database with +C the different byte-level representations indicated below to reduce physical +C storage space. +C +C Symbols in the availability code: +C +C a = field is defined for asteroid records +C c = field is defined for comet records +C 3+= field is defined for DASTCOM3 and later database readers +C 4+= field is defined for DASTCOM4 and later database readers +C 5+= field is defined for DASTCOM5 and later database readers +C +C The classical orbital elements are heliocentric ecliptic. The ecliptic is +C specified by EQUNOX, which should now always be '2000', indicating J2000 +C ecliptic system (IAU76 constants). +C +C To transform from J2000 ecliptic to the original equatorial system used for +C numerical integration (defined by PENAM), use an obliquity angle (epsilon) +C of 84381.448 arcsec. There are slightly different values of epsilon in +C different sets of constants, but this value was used to convert from the +C precise planetary ephemeris equatorial system of PENAM, and so should be +C used to consistently recover the original numerically integrated equatorial +C coordinates. If ecliptic coordinates are to be used directly for high +C precision applications, convert-as-necessary to the intended ecliptic system. +C +C If EQUNOX is instead '1950', an epsilon of 84404.8362512 arc-seconds should +C be used to recover the original integrator equatorial state in the coordinate +C frame of PENAM. +C +C The au->km conversion value for 'au' distance units should be taken from the +C planetary ephemeris indicated by PENAM, along with other constants such +C as mass parameters (GM's). For PENAMs of at least DE430 and later, 1 au is +C 149597870.700 km, by IAU standard. +C +C Time units are in the coordinate time (CT) scale of general relativity, +C defined by the independent variable in the barycentric planetary ephemeris +C equations of motion. This is equivalent to the IAU TDB time-scale. +C +C "1 day" is defined to be 86400 SI seconds. +C +C NOTE #1: non-gravitational parameters A1, A2, A3 are stored in the database +C in units of 10^-8 au/d^2, but returned by this reader package with units of +C au/d^2. Conversion is done in subroutine DXNASGN. This handling is denoted +C in the list below by the "[s:10^-8 au/day^2]" notation, where "s:" denotes +C "stored as". For example, if the database store value of A1 is 1.3453, the +C value of A1 is 1.3453*10^-8 au/day^2, and that will be returned by this +C reader package. A user-developed reader would need to perform the same units +C conversion. +C +C NOTE #2: values are physically stored with minimum appropriate byte-lengths +C in suitable numerical data-types (i.e., integer, floating point), but are +C converted to an array of 8-byte floating-point double-precision values when +C returned to the user by DXREAD(). This can result in additional digits that +C aren't meaningful; for example, when 4-byte floating-point values (seven +C decimal digits) are stored in the 8-byte return array (fifteen decimal +C digits), the eight additional digits can be artifacts of floating point +C representation. Calculations should take this into account and recognize +C the original REAL*4 database values as having at most seven decimal digits +C of precision. +C +C NOTE #3: The non-gravitational A1-A3, DT and related model parameters are as +C described in "Cometary Orbit Determination and Nongravitational Forces", +C D.K. Yeomans, P.W. Chodas, G. Sitarski, S. Szutowicz, M Krolikowska, in +C Comets II, University of Arizona Press (2004), pp. 137-151. +C +C Physically stored values REAL*8 (8-byte IEEE floating precision numeric) +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 801 ac/3+ EPOCH Time of osc. orbital elements solution, JD (CT,TDB) +C 802 ac/3+ CALEPO Time of osc. orbital elements solution, YYYYDDMM.ffff +C 803 ac/3+ MA Mean anomaly at EPOCH, deg (elliptical & hyperbolic cases, +C "9.999999E99" if not available) +C 804 ac/3+ W Argument of periapsis at EPOCH, J2000 ecliptic, deg. +C 805 ac/3+ OM Longitude of ascending node at EPOCH, J2000 ecliptic,deg. +C 806 ac/3+ IN Inclination angle at EPOCH wrt J2000 ecliptic, deg. +C 807 ac/3+ EC Eccentricity at EPOCH +C 808 ac/3+ A Semi-major axis at EPOCH, au +C 809 ac/3+ QR Perihelion distance at EPOCH, au +C 810 ac/3+ TP Perihelion date for QR at EPOCH, JD (CT,TDB) +C 811 ac/3+ TPCAL Perihelion date for QR at EPOCH, format YYYYMMDD.fff +C 812 ac/5+ TPFRAC Decimal (fractional) part of TP for extended precision +C 813 ac/4+ SOLDAT Date orbit solution was performed, JD (CT,TDB) +C +C DERIVED from physically stored REAL*8 (8-byte IEEE floating precision numeric) +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 851 ac/3+ ADIST Aphelion distance at EPOCH, au +C 852 ac/3+ PER Sidereal orbit period @ EPOCH, Julian yr (365.25 d/Jul.yr) +C 853 ac/3+ ANGMOM Specific angular momentum at EPOCH, au^2/D +C 854 ac/3+ N Mean motion, deg/day (elliptical and hyperbolic cases, +C "9.999999E99" if not available) +C 855 ac/3+ DAN Heliocentric distance of ascending node at EPOCH, au +C 856 ac/3+ DDN Heliocentric distance of descending node at EPOCH, au +C 857 ac/3+ L Ecliptic longitude of perihelion at EPOCH, deg. +C 858 ac/3+ B Ecliptic latitude of perihelion at EPOCH, deg. +C +C Physically stored REAL*8 (8-byte IEEE floating precision numeric) +C Requires multiple storage slots +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 899 ac/4+ SRC(01) Square root covariance vector. Vector-stored upper- +C triangular matrix with order {EC,QR,TP,OM,W,IN,{ESTL}}. +C Always reserve enough space (i.e., up to 55 slots) in +C both request and output arrays to hold complete vector. +C +C SRC in matrix form (units are days, radians, au): +C +C EC QR TP OM W IN {ESTL} +C EC e11 e12 e13 e14 e15 e16 +C QR e22 e23 e24 e25 e26 +C TP e33 e34 e35 e36 +C OM e44 e45 e46 +C W e55 e56 +C IN e66 +C {ESTL} +C +C The SRC vector stores the matrix elements from row i and +C column j (i<=j) in vector slot j*(j-1)/2 + i. i.e., upper +C part only, stored by columns: +C +C SRC(1,..)= e11,e12,e22,e13,e23 ... +C +C To obtain a covariance matrix, bottom-fill an SRC matrix +C with zeros to obtain matrix RI. Multiply RI by its +C transpose: +C +C T +C COV = RI * RI +C +C Physically stored values REAL*4 (4-byte IEEE floating precision numeric) +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 401 ac/3+ H Absolute visual magnitude (IAU H-G system) (99=unknown) +C 402 ac/3+ G Mag. slope parm. (IAU H-G)(99=unknown & 0.15 not assumed) +C 403 c/3+ M1 Total absolute magnitude, mag. +C 404 c/3+ M2 Nuclear absolute magnitue, mag. +C 405 c/4+ K1 Total absolute magnitude scaling factor +C 406 c/4+ K2 Nuclear absolute magnitude scaling factor +C 407 c/4+ PHCOF Phase coefficient for K2= 5 +C 408 ac/3+ A1 Non-grav. accel., radial component, [s:10^-8 au/day^2] +C 409 ac/3+ A2 Non-grav. accel., transverse component,[s:10^-8 au/day^2] +C 410 ac/4+ A3 Non-grav. accel., normal component, [s:10^-8 au/day^2] +C 411 c/4+ DT Non-grav. lag/delay parameter, days +C 412 ac/5+ R0 Non-grav. model constant, normalizing distance, au +C 413 ac/5+ ALN Non-grav. model constant, normalizing factor +C 414 ac/5+ NM Non-grav. model constant, exponent m +C 415 ac/5+ NN Non-grav. model constant, exponent n +C 416 ac/5+ NK Non-grav. model constant, exponent k +C 417 c/4+ S0 Center-of-light estimated offset at 1 au, km +C 418 c/5+ TCL Center-of-light start-time offset, d since "ref.time" +C 419 a /5+ LGK Surface thermal conductivity log_10(k), (W/m/K) +C 420 ac/5+ RHO Bulk density, kg/m^3 +C 421 ac/5+ AMRAT Solar pressure model, area/mass ratio, m^2/kg +C 422 c/5+ AJ1 Jet 1 acceleration, au/d^2 +C 423 c/5+ AJ2 Jet 2 acceleration, au/d^2 +C 424 c/5+ ET1 Thrust angle, colatitude of jet 1, deg. +C 425 c/5+ ET2 Thrust angle, colatitude of jet 2, deg. +C 426 c/5+ DTH Jet model diurnal lag angle, deg. (delta_theta) +C 427 ac/5+ ALF Spin pole orientation, RA, deg. +C 428 ac/5+ DEL Spin pole orientation, DEC, deg. +C 429 ac/5+ SPHLM3 Earth gravity sph. harm. model limit, Earth radii +C 430 ac/5+ SPHLM5 Jupiter grav. sph. harm. model limit, Jupiter radii +C 431 ac/3+ RP Object rotational period, hrs +C 432 ac/3+ GM Object mass parameter, km^3/s^2 +C 433 ac/3+ RAD Object mean radius, km +C 434 ac/5+ EXTNT1 Triaxial ellipsoid, axis 1/largest equat. extent, km +C 435 ac/5+ EXTNT2 Triaxial ellipsoid, axis 2/smallest equat. extent, km +C 436 ac/5+ EXTNT3 Triaxial ellipsoid, axis 3/polar extent, km +C 437 ac/4+ MOID Earth MOID at EPOCH time, au; '99' if not computed +C 438 ac/3+ ALBEDO Geometric visual albedo, 99 if unknown +C 439 a /3+ BVCI B-V color index, mag., 99 if unknown +C 440 a /5+ UBCI U-B color index, mag., 99 if unknown +C 441 a /5+ IRCI I-R color index, mag., 99 if unknown +C 442 ac/4+ RMSW RMS of weighted optical residuals, arcsec +C 443 ac/5+ RMSU RMS of unweighted optical residuals, arcsec +C 444 ac/5+ RMSN RMS of normalized optical residuals +C 445 ac/5+ RMSNT RMS of all normalized residuals +C 446 a /5+ RMSH RMS of abs. visual magnitude (H) residuals, mag. +C 447 c/5+ RMSMT RMS of MT estimate residuals, mag. +C 448 c/5+ RMSMN RMS of MN estimate residuals, mag. +C +C Physically stored values INTEGER*4 (4-byte integer numeric) +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 201 ac/3+ NO Logical record-number of this object in DASTCOM +C 202 ac/4+ NOBS Number of observations of all types used in orbit soln. +C 203 ac/4+ OBSFRST Start-date of observations used in fit, YYYYMMDD +C 204 ac/4+ OBSLAST Stop-date of observations used in fit, YYYYMMDD +C +C Physically stored values INTEGER*1 (1-byte signed integers) +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 101 ac/5+ PRELTV Planet relativity "bit-switch" byte: bits 0-7 are set to +C 1 if relativity for corresponding planet was computed, +C 0 if not. For example, if Earth & Jupiter, FORTRAN(95) +C statement IBITS(PRELTV,J,1) should return 1 when J=2 or +C J=4, but zero for every other J through 7. No provision +C for supporting Pluto relativity. +C 102 ac/5+ SPHMX3 Earth grav. model max. degree; 0=point-mass, 2= J2 only, +C 3= up to J3 zonal, 22= 2x2 field, 33=3x3 field, etc. +C 103 ac/5+ SPHMX5 Jupiter grav. max. deg.; 0=point-mass, 2= J2 only, +C 3= up to J3 zonal, 22= 2x2 field, 33=3x3 field, etc. +C 104 ac/5+ JGSEP Galilean satellites used as sep. perturbers; 0=no 1=yes +C 105 ac/5+ TWOBOD Two-body orbit model flag; 0=no 1=yes +C 106 ac/5+ NSATS Number of satellites; 99 if unknown. +C 107 ac/4+ UPARM Orbit condition code; 99 if not computed +C 108 ac/4+ LSRC Length of square-root cov. vector SRC (# elements used) +C +C Physically stored values INTEGER*2 (2-byte integers) +C +C CODE avail Label Definition +C ---- ----- ------- --------------------------------------------------------- +C 151 c/3+ IPYR Perihelion year (i.e., 1976, 2012, 2018, etc.) +C 152 ac/3+ NDEL Number of radar delay measurements used in orbit soln. +C 153 ac/3+ NDOP Number of radar Doppler measurements used in orbit soln. +C 154 c/5+ NOBSMT Number of magnitude measurements used in total mag. soln. +C 155 c/5+ NOBSMN Number of magnitude measurements used in nuc. mag. soln. +C 156 c/3+ COMNUM IAU comet number (parsed from DESIG) +C +C Physically stored character data return in CHOUT argument: +C 'length' is the maximum number of characters in the field +C +C CODE avail length Label Definition +C ---- ----- ------- ------ --------------------------------------------------- +C 001 ac/3+ 4 EQUNOX Equinox of orbital elements ('1950' or '2000') +C 002 ac/4+ 6 PENAM Planetary ephemeris ID/name +C 003 ac/3+ 12 SBNAM Small-body perturber ephemeris ID/name +C 004 a /3 5 SPTYPT Tholen spectral type +C 005 a /4+ 5 SPTYPS SMASS-II spectral type +C 006 ac/3+ 9 DARC Data arc span (year-year, OR integer # of days) +C 007 a /3+ 41 COMNT1 Asteroid comment line #1 +C 008 a /3+ 80 COMNT2 Asteroid comment line #2 +C 009 c/3+ 49 COMNT3 Comet comment line #1 +C 010 c/3+ 80 COMNT4 Comet comment line #2 +C 011 ac/3+ 13 DESIG Object designation +C 012 ac/4+ 14 ESTL Dynamic parameter estimation list. Last symbol set +C to '+' if list is too long for field; check +C object record comments field for full list. +C 013 ac/3+ 10 IREF Solution reference/ID/name +C 014 ac/3+ 29 NAME Object name + + +DASTCOM5 BYTE MAP + + The following is an inclusion of './dastcom5/doc/dastcom5.map', which will + always be the definitive listing: + + DASTCOM5 Binary Record Structure + +Asteroid Header Record : 835 bytes | Comet Header Record : 976 bytes +____________________________________|____________________________________ + Bytes reserved : 86 | Bytes reserved : 82 + Bytes undefined : 749 | Bytes undefined : 894 + | +Name Type Bytes Cumulative | Name Type Bytes Cumulative +------- ------- ------ ---------- | ------- ------- ------ ---------- +IBIAS1 I 4 4 | IBIAS2 I 4 4 +BEGINP C 8*3=24 28 | BEGINP C 8*3=24 28 +ENDPT C 8*3=24 52 | ENDPT C 8*3=24 52 +CALDATE C 19 71 | CALDATE C 19 71 +JDDATE D 8 79 | JDDATE D 8 79 +FTYP C 1 80 | FTYP C 1 80 +BYTE2A I 2 82 | BYTE2C I 2 82 +IBIAS0 I 4 86 | + - 749 835 | - 894 976 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + NOTES on DASTCOM5 headers + + 1. ENDPT and BEGINP character strings contained the first and last + logical record boundaries for the 3 categories of object: + IAU-numbered asteroids, unnumbered asteroids, and comets. + + Because the database is issued in two files (DAST5 and DCOM5), + comet header BND() is zero-filled for DAST5 and asteroid header + BND() is zero-filled for DCOM5. + + Example: + + DAST5: BEGINP= '000000010050000100000000' + |BND(4)||BND(5)||NOCOMS| + + ENDPT = '003332730075428200000000' + |BND(1)||BND(2)||NOCOMS| + + DCOM5: BEGINP= '000000000000000000900001' + |_NO_ASTEROIDS_||BND(6)| + + ENDPT = '000000000000000000903900' + |_NO_ASTEROIDS_||BND(3)| + + 2. CALDATE is character-format creation date: "YYYY-MM-DD_HH:MM:SS" + JDDATE is Julian astronomical day creation date (REAL*8 numeric) + + 3. IBIAS1 & IBIAS2 and new IBIAS0 + + Since the database is issued in two files (DAST5 and DCOM5), there + is no IBIAS2 field in the DAST5 header and no IBIAS0 or IBIAS1 + fields in the DCOM5 header. + + physical record = user logical record - IBIAS + + 4. For byte #80 of header records (character), + + 'A' denotes DASTCOM3, + 'C' denotes DASTCOM4, + '5' denotes DASTCOM5 + + The database type variations will be detected & handled in reader(s). + + 5. Byte 81-82 of each header is a two-byte integer always set to 26901 + and necessary for database structure tests. + + 6. may be null, character ' ', or anything + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +Asteroid Record : 835 bytes | Comet Record : 976 bytes +____________________________________|____________________________________ + Bytes reserved : 835 | Bytes reserved : 976 + Bytes undefined: 0 | Bytes undefined: 0 + | +Name Type Bytes Cumulative | Name Type Bytes Cumulative +------- ------- ------ ---------- | ------ ------- ------ ---------- +NO I 4 4 | NO I 4 4 +NOBS I 4 8 | NOBS I 4 8 +OBSFRST I 4 12 | OBSFRST I 4 12 +OBSLAST I 4 16 | OBSLAST I 4 16 +EPOCH D 8 24 | EPOCH D 8 24 +CALEPO D 8 32 | CALEPO D 8 32 +MA D 8 40 | MA D 8 40 +W D 8 48 | W D 8 48 +OM D 8 56 | OM D 8 56 +IN D 8 64 | IN D 8 64 +EC D 8 72 | EC D 8 72 +A D 8 80 | A D 8 80 +QR D 8 88 | QR D 8 88 +TP D 8 96 | TP D 8 96 +TPCAL D 8 104 | TPCAL D 8 104 +TPFRAC D 8 112 | TPFRAC D 8 112 +SOLDAT D 8 120 | SOLDAT D 8 120 +SRC(1-45) D 45*8=360 480 | SRC(1-55) D 55*8= 440 560 +PRELTV I 1 481 | PRELTV I 1 561 +SPHMX3 I 1 482 | SPHMX3 I 1 562 +SPHMX5 I 1 483 | SPHMX5 I 1 563 +JGSEP I 1 484 | JGSEP I 1 564 +TWOBOD I 1 485 | TWOBOD I 1 565 +NSATS I 1 486 | NSATS I 1 566 +UPARM I 1 487 | UPARM I 1 567 +LSRC I 1 488 | LSRC I 1 568 + | IPYR I 2 570 +NDEL I 2 490 | NDEL I 2 572 +NDOP I 2 492 | NDOP I 2 574 + | NOBSMT I 2 576 + | NOBSMN I 2 578 +H R 4 496 | H R 4 582 +G R 4 500 | G R 4 586 + | M1 (MT) R 4 590 + | M2 (MN) R 4 594 + | K1 (MTS) R 4 598 + | K2 (MNS) R 4 602 + | PHCOF (MNP)R 4 606 +A1 R 4 504 | A1 R 4 610 +A2 R 4 508 | A2 R 4 614 +A3 R 4 512 | A3 R 4 618 + | DT R 4 622 +R0 R 4 516 | R0 R 4 626 +ALN R 4 520 | ALN R 4 630 +NM R 4 524 | NM R 4 634 +NN R 4 528 | NN R 4 638 +NK R 4 532 | NK R 4 642 + | S0 R 4 646 + | TCL R 4 650 +LGK R 4 536 | +RHO R 4 540 | RHO R 4 654 +AMRAT R 4 544 | AMRAT R 4 658 + | AJ1 R 4 662 + | AJ2 R 4 666 + | ET1 R 4 670 + | ET2 R 4 674 + | DTH R 4 678 +ALF R 4 548 | ALF R 4 682 +DEL R 4 552 | DEL R 4 686 +SPHLM3 R 4 556 | SPHLM3 R 4 690 +SPHLM5 R 4 560 | SPHLM5 R 4 694 +RP R 4 564 | RP R 4 698 +GM R 4 568 | GM R 4 702 +RAD R 4 572 | RAD R 4 706 +EXTNT1 R 4 576 | EXTNT1 R 4 710 +EXTNT2 R 4 580 | EXTNT2 R 4 714 +EXTNT3 R 4 584 | EXTNT3 R 4 718 +MOID R 4 588 | MOID R 4 722 +ALBEDO R 4 592 | ALBEDO R 4 726 +BVCI R 4 596 | +UBCI R 4 600 | +IRCI R 4 604 | +RMSW R 4 608 | RMSW R 4 730 +RMSU R 4 612 | RMSU R 4 734 +RMSN R 4 616 | RMSN R 4 738 +RMSNT R 4 620 | RMSNT R 4 742 +RMSH R 4 624 | + | RMSMT R 4 746 + | RMSMN R 4 750 +EQUNOX C 4 628 | EQUNOX C 4 754 +PENAM C 6 634 | PENAM C 6 760 +SBNAM C 12 646 | SBNAM C 12 772 +SPTYPT C 5 651 | +SPTYPS C 5 656 | +DARC C 9 665 | DARC C 9 781 +COMNT1 C 41 706 | +COMNT2 C 80 786 | + | COMNT3 C 49 830 + | COMNT2 C 80 910 +DESIG C 13 799 | DESIG C 13 923 +ASTEST C 8 807 | COMEST C 14 937 +IREF C 10 817 | IREF C 10 947 +ASTNAM C 18 835 | COMNAM C 29 976 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 'D' type denotes floating-point DOUBLE PRECISION (8-byte REAL*8) + 'I' type denotes INTEGER of indicated byte-length (1,2,or 4) + 'R' type denotes floating-point REAL*4 (4-byte) + 'C' type denotes CHARACTER data of indicated length +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +CONTACT + + If any bugs are found, or problems are encountered compiling or using the + FORTRAN code provided, with compiler X on platform Y, let us know: + + e-mail: Jon.D.Giorgini@jpl.nasa.gov + + If you are able to successfully build and link on a different OS with a + different compiler, let us know how it went and what you had to do. Credit + will be given where credit is due. + + This software is primarily intended for our internal use (and we aren't a + programming group) so is being made available "as-is". However, some issues + might readily be resolved if access to compiler X on platform Y is possible. + + Little or no support is available to assist re-implementation outside JPL in + other languages, or resolve problems with significantly altered versions of + the distribution. + +COPYRIGHT + +Copyright 2013, by the California Institute of Technology. ALL RIGHTS RESERVED. +United States Government Sponsorship acknowledged. Any commercial use must be +negotiated with the Office of Technology Transfer at the California Institute +of Technology. + +This software may be subject to U.S. export control laws. By accepting this +software, the user agrees to comply with all applicable U.S. export laws and +regulations. User has the responsibility to obtain export licenses, or other +export authority as may be required before exporting such information to +foreign countries or providing access to foreign persons. diff --git a/sbpy/dastcom5/__init__.py b/sbpy/dastcom5/__init__.py new file mode 100644 index 000000000..59c3d87dd --- /dev/null +++ b/sbpy/dastcom5/__init__.py @@ -0,0 +1,13 @@ +"""Code related to NEOs. + +Functions related to NEOs and different NASA APIs. +All of them are coded as part of SOCIS 2017 proposal. + +Notes +----- + +The orbits returned by the functions in this package are in the +:py:class:`~poliastro.frames.HeliocentricEclipticJ2000` frame. + +""" +from poliastro.neos import neows, dastcom5 # flake8: noqa diff --git a/sbpy/dastcom5/dastcom5.py b/sbpy/dastcom5/dastcom5.py new file mode 100644 index 000000000..220c2b26e --- /dev/null +++ b/sbpy/dastcom5/dastcom5.py @@ -0,0 +1,590 @@ +"""NEOs orbit from DASTCOM5 database. + +""" +import os +import re +import urllib.request +import zipfile + +import astropy.units as u +import numpy as np +import pandas as pd +from astropy.time import Time + +from poliastro.bodies import Sun +from poliastro.frames import HeliocentricEclipticJ2000 +from poliastro.twobody.angles import M_to_nu +from poliastro.twobody.orbit import Orbit + +AST_DTYPE = np.dtype( + [ + ("NO", np.int32), + ("NOBS", np.int32), + ("OBSFRST", np.int32), + ("OBSLAST", np.int32), + ("EPOCH", np.float64), + ("CALEPO", np.float64), + ("MA", np.float64), + ("W", np.float64), + ("OM", np.float64), + ("IN", np.float64), + ("EC", np.float64), + ("A", np.float64), + ("QR", np.float64), + ("TP", np.float64), + ("TPCAL", np.float64), + ("TPFRAC", np.float64), + ("SOLDAT", np.float64), + ("SRC1", np.float64), + ("SRC2", np.float64), + ("SRC3", np.float64), + ("SRC4", np.float64), + ("SRC5", np.float64), + ("SRC6", np.float64), + ("SRC7", np.float64), + ("SRC8", np.float64), + ("SRC9", np.float64), + ("SRC10", np.float64), + ("SRC11", np.float64), + ("SRC12", np.float64), + ("SRC13", np.float64), + ("SRC14", np.float64), + ("SRC15", np.float64), + ("SRC16", np.float64), + ("SRC17", np.float64), + ("SRC18", np.float64), + ("SRC19", np.float64), + ("SRC20", np.float64), + ("SRC21", np.float64), + ("SRC22", np.float64), + ("SRC23", np.float64), + ("SRC24", np.float64), + ("SRC25", np.float64), + ("SRC26", np.float64), + ("SRC27", np.float64), + ("SRC28", np.float64), + ("SRC29", np.float64), + ("SRC30", np.float64), + ("SRC31", np.float64), + ("SRC32", np.float64), + ("SRC33", np.float64), + ("SRC34", np.float64), + ("SRC35", np.float64), + ("SRC36", np.float64), + ("SRC37", np.float64), + ("SRC38", np.float64), + ("SRC39", np.float64), + ("SRC40", np.float64), + ("SRC41", np.float64), + ("SRC42", np.float64), + ("SRC43", np.float64), + ("SRC44", np.float64), + ("SRC45", np.float64), + ("PRELTV", np.int8), + ("SPHMX3", np.int8), + ("SPHMX5", np.int8), + ("JGSEP", np.int8), + ("TWOBOD", np.int8), + ("NSATS", np.int8), + ("UPARM", np.int8), + ("LSRC", np.int8), + ("NDEL", np.int16), + ("NDOP", np.int16), + ("H", np.float32), + ("G", np.float32), + ("A1", np.float32), + ("A2", np.float32), + ("A3", np.float32), + ("R0", np.float32), + ("ALN", np.float32), + ("NM", np.float32), + ("NN", np.float32), + ("NK", np.float32), + ("LGK", np.float32), + ("RHO", np.float32), + ("AMRAT", np.float32), + ("ALF", np.float32), + ("DEL", np.float32), + ("SPHLM3", np.float32), + ("SPHLM5", np.float32), + ("RP", np.float32), + ("GM", np.float32), + ("RAD", np.float32), + ("EXTNT1", np.float32), + ("EXTNT2", np.float32), + ("EXTNT3", np.float32), + ("MOID", np.float32), + ("ALBEDO", np.float32), + ("BVCI", np.float32), + ("UBCI", np.float32), + ("IRCI", np.float32), + ("RMSW", np.float32), + ("RMSU", np.float32), + ("RMSN", np.float32), + ("RMSNT", np.float32), + ("RMSH", np.float32), + ("EQUNOX", "|S4"), + ("PENAM", "|S6"), + ("SBNAM", "|S12"), + ("SPTYPT", "|S5"), + ("SPTYPS", "|S5"), + ("DARC", "|S9"), + ("COMNT1", "|S41"), + ("COMNT2", "|S80"), + ("DESIG", "|S13"), + ("ASTEST", "|S8"), + ("IREF", "|S10"), + ("ASTNAM", "|S18"), + ] +) + +COM_DTYPE = np.dtype( + [ + ("NO", np.int32), + ("NOBS", np.int32), + ("OBSFRST", np.int32), + ("OBSLAST", np.int32), + ("EPOCH", np.float64), + ("CALEPO", np.float64), + ("MA", np.float64), + ("W", np.float64), + ("OM", np.float64), + ("IN", np.float64), + ("EC", np.float64), + ("A", np.float64), + ("QR", np.float64), + ("TP", np.float64), + ("TPCAL", np.float64), + ("TPFRAC", np.float64), + ("SOLDAT", np.float64), + ("SRC1", np.float64), + ("SRC2", np.float64), + ("SRC3", np.float64), + ("SRC4", np.float64), + ("SRC5", np.float64), + ("SRC6", np.float64), + ("SRC7", np.float64), + ("SRC8", np.float64), + ("SRC9", np.float64), + ("SRC10", np.float64), + ("SRC11", np.float64), + ("SRC12", np.float64), + ("SRC13", np.float64), + ("SRC14", np.float64), + ("SRC15", np.float64), + ("SRC16", np.float64), + ("SRC17", np.float64), + ("SRC18", np.float64), + ("SRC19", np.float64), + ("SRC20", np.float64), + ("SRC21", np.float64), + ("SRC22", np.float64), + ("SRC23", np.float64), + ("SRC24", np.float64), + ("SRC25", np.float64), + ("SRC26", np.float64), + ("SRC27", np.float64), + ("SRC28", np.float64), + ("SRC29", np.float64), + ("SRC30", np.float64), + ("SRC31", np.float64), + ("SRC32", np.float64), + ("SRC33", np.float64), + ("SRC34", np.float64), + ("SRC35", np.float64), + ("SRC36", np.float64), + ("SRC37", np.float64), + ("SRC38", np.float64), + ("SRC39", np.float64), + ("SRC40", np.float64), + ("SRC41", np.float64), + ("SRC42", np.float64), + ("SRC43", np.float64), + ("SRC44", np.float64), + ("SRC45", np.float64), + ("SRC46", np.float64), + ("SRC47", np.float64), + ("SRC48", np.float64), + ("SRC49", np.float64), + ("SRC50", np.float64), + ("SRC51", np.float64), + ("SRC52", np.float64), + ("SRC53", np.float64), + ("SRC54", np.float64), + ("SRC55", np.float64), + ("PRELTV", np.int8), + ("SPHMX3", np.int8), + ("SPHMX5", np.int8), + ("JGSEP", np.int8), + ("TWOBOD", np.int8), + ("NSATS", np.int8), + ("UPARM", np.int8), + ("LSRC", np.int8), + ("IPYR", np.int16), + ("NDEL", np.int16), + ("NDOP", np.int16), + ("NOBSMT", np.int16), + ("NOBSMN", np.int16), + ("H", np.float32), + ("G", np.float32), + ("M1 (MT)", np.float32), + ("M2 (MN)", np.float32), + ("K1 (MTSMT)", np.float32), + ("K2 (MNSMT)", np.float32), + ("PHCOF (MNP)", np.float32), + ("A1", np.float32), + ("A2", np.float32), + ("A3", np.float32), + ("DT", np.float32), + ("R0", np.float32), + ("ALN", np.float32), + ("NM", np.float32), + ("NN", np.float32), + ("NK", np.float32), + ("S0", np.float32), + ("TCL", np.float32), + ("RHO", np.float32), + ("AMRAT", np.float32), + ("AJ1", np.float32), + ("AJ2", np.float32), + ("ET1", np.float32), + ("ET2", np.float32), + ("DTH", np.float32), + ("ALF", np.float32), + ("DEL", np.float32), + ("SPHLM3", np.float32), + ("SPHLM5", np.float32), + ("RP", np.float32), + ("GM", np.float32), + ("RAD", np.float32), + ("EXTNT1", np.float32), + ("EXTNT2", np.float32), + ("EXTNT3", np.float32), + ("MOID", np.float32), + ("ALBEDO", np.float32), + ("RMSW", np.float32), + ("RMSU", np.float32), + ("RMSN", np.float32), + ("RMSNT", np.float32), + ("RMSMT", np.float32), + ("RMSMN", np.float32), + ("EQUNOX", "|S4"), + ("PENAM", "|S6"), + ("SBNAM", "|S12"), + ("DARC", "|S9"), + ("COMNT3", "|S49"), + ("COMNT2", "|S80"), + ("DESIG", "|S13"), + ("COMEST", "|S14"), + ("IREF", "|S10"), + ("COMNAM", "|S29"), + ] +) + +POLIASTRO_LOCAL_PATH = os.path.join(os.path.expanduser("~"), ".poliastro") +DBS_LOCAL_PATH = os.path.join(POLIASTRO_LOCAL_PATH, "dastcom5", "dat") +AST_DB_PATH = os.path.join(DBS_LOCAL_PATH, "dast5_le.dat") +COM_DB_PATH = os.path.join(DBS_LOCAL_PATH, "dcom5_le.dat") + +FTP_DB_URL = "ftp://ssd.jpl.nasa.gov/pub/ssd/" + + +def asteroid_db(): + """Return complete DASTCOM5 asteroid database. + + Returns + ------- + database : numpy.ndarray + Database with custom dtype. + + """ + with open(AST_DB_PATH, "rb") as f: + f.seek(835, os.SEEK_SET) + data = np.fromfile(f, dtype=AST_DTYPE) + return data + + +def comet_db(): + """Return complete DASTCOM5 comet database. + + Returns + ------- + database : numpy.ndarray + Database with custom dtype. + + """ + with open(COM_DB_PATH, "rb") as f: + f.seek(976, os.SEEK_SET) + data = np.fromfile(f, dtype=COM_DTYPE) + return data + + +def orbit_from_name(name): + """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a name. + + Retrieve info from JPL DASTCOM5 database. + + Parameters + ---------- + name : str + NEO name. + + Returns + ------- + orbit : list (~poliastro.twobody.orbit.Orbit) + NEO orbits. + + """ + records = record_from_name(name) + orbits = [] + for record in records: + orbits.append(orbit_from_record(record)) + return orbits + + +def orbit_from_record(record): + """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a record. + + Retrieve info from JPL DASTCOM5 database. + + Parameters + ---------- + record : int + Object record. + + Returns + ------- + orbit : ~poliastro.twobody.orbit.Orbit + NEO orbit. + + """ + body_data = read_record(record) + a = body_data["A"].item() * u.au + ecc = body_data["EC"].item() * u.one + inc = body_data["IN"].item() * u.deg + raan = body_data["OM"].item() * u.deg + argp = body_data["W"].item() * u.deg + m = body_data["MA"].item() * u.deg + nu = M_to_nu(m, ecc) + epoch = Time(body_data["EPOCH"].item(), format="jd", scale="tdb") + + orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch) + orbit._frame = HeliocentricEclipticJ2000(obstime=epoch) + return orbit + + +def record_from_name(name): + """Search `dastcom.idx` and return logical records that match a given string. + + Body name, SPK-ID, or alternative designations can be used. + + Parameters + ---------- + name : str + Body name. + + Returns + ------- + records : list (int) + DASTCOM5 database logical records matching str. + + """ + records = [] + lines = string_record_from_name(name) + for line in lines: + records.append(int(line[:6].lstrip())) + return records + + +def string_record_from_name(name): + """Search `dastcom.idx` and return body full record. + + Search DASTCOM5 index and return body records that match string, + containing logical record, name, alternative designations, SPK-ID, etc. + + Parameters + ---------- + name : str + Body name. + + Returns + ------- + lines: list(str) + Body records + """ + + idx_path = os.path.join(DBS_LOCAL_PATH, "dastcom.idx") + lines = [] + with open(idx_path, "r") as inF: + for line in inF: + if re.search(r"\b" + name.casefold() + r"\b", line.casefold()): + lines.append(line) + return lines + + +def read_headers(): + """Read `DASTCOM5` headers and return asteroid and comet headers. + + Headers are two numpy arrays with custom dtype. + + Returns + ------- + ast_header, com_header : tuple (numpy.ndarray) + DASTCOM5 headers. + + """ + + ast_path = os.path.join(DBS_LOCAL_PATH, "dast5_le.dat") + ast_dtype = np.dtype( + [ + ("IBIAS1", np.int32), + ("BEGINP1", "|S8"), + ("BEGINP2", "|S8"), + ("BEGINP3", "|S8"), + ("ENDPT1", "|S8"), + ("ENDPT2", "|S8"), + ("ENDPT3", "|S8"), + ("CALDATE", "|S19"), + ("JDDATE", np.float64), + ("FTYP", "|S1"), + ("BYTE2A", np.int16), + ("IBIAS0", np.int32), + ] + ) + + with open(ast_path, "rb") as f: + ast_header = np.fromfile(f, dtype=ast_dtype, count=1) + + com_path = os.path.join(DBS_LOCAL_PATH, "dcom5_le.dat") + com_dtype = np.dtype( + [ + ("IBIAS2", np.int32), + ("BEGINP1", "|S8"), + ("BEGINP2", "|S8"), + ("BEGINP3", "|S8"), + ("ENDPT1", "|S8"), + ("ENDPT2", "|S8"), + ("ENDPT3", "|S8"), + ("CALDATE", "|S19"), + ("JDDATE", np.float64), + ("FTYP", "|S1"), + ("BYTE2C", np.int16), + ] + ) + + with open(com_path, "rb") as f: + com_header = np.fromfile(f, dtype=com_dtype, count=1) + + return ast_header, com_header + + +def read_record(record): + """Read `DASTCOM5` record and return body data. + + Body data consists of numpy array with custom dtype. + + Parameters + ---------- + record : int + Body record. + + Returns + ------- + body_data : numpy.ndarray + Body information. + + """ + ast_header, com_header = read_headers() + ast_path = os.path.join(DBS_LOCAL_PATH, "dast5_le.dat") + com_path = os.path.join(DBS_LOCAL_PATH, "dcom5_le.dat") + # ENDPT1 indicates end of numbered asteroids records + if record <= int(ast_header["ENDPT2"][0].item()): + # ENDPT2 indicates end of unnumbered asteroids records + if record <= int(ast_header["ENDPT1"][0].item()): + # phis_rec = record_size * (record_number - IBIAS - 1 (header record)) + phis_rec = 835 * (record - ast_header["IBIAS0"][0].item() - 1) + else: + phis_rec = 835 * (record - ast_header["IBIAS1"][0].item() - 1) + + with open(ast_path, "rb") as f: + f.seek(phis_rec, os.SEEK_SET) + body_data = np.fromfile(f, dtype=AST_DTYPE, count=1) + else: + phis_rec = 976 * (record - com_header["IBIAS2"][0].item() - 1) + with open(com_path, "rb") as f: + f.seek(phis_rec, os.SEEK_SET) + body_data = np.fromfile(f, dtype=COM_DTYPE, count=1) + return body_data + + +def download_dastcom5(): + """Downloads DASTCOM5 database. + + Downloads and unzip DASTCOM5 file in default poliastro path (~/.poliastro). + + """ + + dastcom5_dir = os.path.join(POLIASTRO_LOCAL_PATH, "dastcom5") + dastcom5_zip_path = os.path.join(POLIASTRO_LOCAL_PATH, "dastcom5.zip") + + if os.path.isdir(dastcom5_dir): + raise FileExistsError( + "dastcom5 is already created in " + os.path.abspath(dastcom5_dir) + ) + if not zipfile.is_zipfile(dastcom5_zip_path): + if not os.path.isdir(POLIASTRO_LOCAL_PATH): + os.makedirs(POLIASTRO_LOCAL_PATH) + + urllib.request.urlretrieve( + FTP_DB_URL + "dastcom5.zip", dastcom5_zip_path, _show_download_progress + ) + with zipfile.ZipFile(dastcom5_zip_path) as myzip: + myzip.extractall(POLIASTRO_LOCAL_PATH) + + +def _show_download_progress(transferred, block, totalsize): + trans_mb = transferred * block / (1024 * 1024) + total_mb = totalsize / (1024 * 1024) + print("%.2f MB / %.2f MB" % (trans_mb, total_mb), end="\r", flush=True) + + +def entire_db(): + """Return complete DASTCOM5 database. + + Merge asteroid and comet databases, only with fields + related to orbital data, discarding the rest. + + Returns + ------- + database : numpy.ndarray + Database with custom dtype. + + """ + ast_database = asteroid_db() + com_database = comet_db() + + ast_database = pd.DataFrame( + ast_database[ + list(ast_database.dtype.names[:17]) + + list(ast_database.dtype.names[-4:-3]) + + list(ast_database.dtype.names[-2:]) + ] + ) + ast_database.rename( + columns={"ASTNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, inplace=True + ) + com_database = pd.DataFrame( + com_database[ + list(com_database.dtype.names[:17]) + + list(com_database.dtype.names[-4:-3]) + + list(com_database.dtype.names[-2:]) + ] + ) + com_database.rename( + columns={"COMNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, inplace=True + ) + df = ast_database.append(com_database, ignore_index=True) + df[["NAME", "DESIG", "IREF"]] = df[["NAME", "DESIG", "IREF"]].apply( + lambda x: x.str.strip().str.decode("utf-8") + ) + return df From 19a15aa7cc6155f1f81daa4e4fbbcbce8e8e286e Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Wed, 27 Feb 2019 21:06:39 +0530 Subject: [PATCH 02/16] Fix the module for sbpy --- sbpy/dastcom5/__init__.py | 12 ++----- sbpy/dastcom5/dastcom5.py | 67 ++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/sbpy/dastcom5/__init__.py b/sbpy/dastcom5/__init__.py index 59c3d87dd..eeee6f0b5 100644 --- a/sbpy/dastcom5/__init__.py +++ b/sbpy/dastcom5/__init__.py @@ -1,13 +1,7 @@ -"""Code related to NEOs. +"""Code related to DASTCOM5 service. Functions related to NEOs and different NASA APIs. -All of them are coded as part of SOCIS 2017 proposal. - -Notes ------ - -The orbits returned by the functions in this package are in the -:py:class:`~poliastro.frames.HeliocentricEclipticJ2000` frame. +All of them are coded as part of SOCIS 2017 proposal for poliastro by Antonio Hidalgo. """ -from poliastro.neos import neows, dastcom5 # flake8: noqa +from sbpy.dastcom5 import dastcom5 diff --git a/sbpy/dastcom5/dastcom5.py b/sbpy/dastcom5/dastcom5.py index 220c2b26e..e40710f77 100644 --- a/sbpy/dastcom5/dastcom5.py +++ b/sbpy/dastcom5/dastcom5.py @@ -1,6 +1,3 @@ -"""NEOs orbit from DASTCOM5 database. - -""" import os import re import urllib.request @@ -10,11 +7,8 @@ import numpy as np import pandas as pd from astropy.time import Time - -from poliastro.bodies import Sun -from poliastro.frames import HeliocentricEclipticJ2000 -from poliastro.twobody.angles import M_to_nu -from poliastro.twobody.orbit import Orbit +from astropy.table import Table +import astropy.units as u AST_DTYPE = np.dtype( [ @@ -281,8 +275,8 @@ ] ) -POLIASTRO_LOCAL_PATH = os.path.join(os.path.expanduser("~"), ".poliastro") -DBS_LOCAL_PATH = os.path.join(POLIASTRO_LOCAL_PATH, "dastcom5", "dat") +SBPY_LOCAL_PATH = os.path.join(os.path.expanduser("~"), ".sbpy") +DBS_LOCAL_PATH = os.path.join(SBPY_LOCAL_PATH, "dastcom5", "dat") AST_DB_PATH = os.path.join(DBS_LOCAL_PATH, "dast5_le.dat") COM_DB_PATH = os.path.join(DBS_LOCAL_PATH, "dcom5_le.dat") @@ -320,7 +314,7 @@ def comet_db(): def orbit_from_name(name): - """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a name. + """Return :py:class:`~astropy.table.Table` given a name. Retrieve info from JPL DASTCOM5 database. @@ -331,19 +325,18 @@ def orbit_from_name(name): Returns ------- - orbit : list (~poliastro.twobody.orbit.Orbit) - NEO orbits. + Table : ~astropy.table.Table + Near Earth Asteroid/Comet orbit parameters, all stacked. """ records = record_from_name(name) - orbits = [] - for record in records: - orbits.append(orbit_from_record(record)) - return orbits + orbits = [self.orbit_from_record(rec) for rec in records] + tbl = Table(orbits) + return tbl def orbit_from_record(record): - """Return :py:class:`~poliastro.twobody.orbit.Orbit` given a record. + """Return :py:class:`~astropy.table.Table` given a record. Retrieve info from JPL DASTCOM5 database. @@ -354,23 +347,23 @@ def orbit_from_record(record): Returns ------- - orbit : ~poliastro.twobody.orbit.Orbit - NEO orbit. + Table : ~astropy.table.Table + Near Earth Asteroid/Comet orbit parameters. - """ + """ body_data = read_record(record) - a = body_data["A"].item() * u.au - ecc = body_data["EC"].item() * u.one - inc = body_data["IN"].item() * u.deg - raan = body_data["OM"].item() * u.deg - argp = body_data["W"].item() * u.deg - m = body_data["MA"].item() * u.deg - nu = M_to_nu(m, ecc) + a = body_data["A"].item() + ecc = body_data["EC"].item() + inc = body_data["IN"].item() + raan = body_data["OM"].item() + argp = body_data["W"].item() + m = body_data["MA"].item() epoch = Time(body_data["EPOCH"].item(), format="jd", scale="tdb") + column2 = (record, a, ecc, inc, raan, argp, m, epoch) + column1 = ("record", "a", "ecc", "inc", "raan", "argp", "m", "EPOCH") + data = Table(rows=[column1, column2]) - orbit = Orbit.from_classical(Sun, a, ecc, inc, raan, argp, nu, epoch) - orbit._frame = HeliocentricEclipticJ2000(obstime=epoch) - return orbit + return data def record_from_name(name): @@ -520,26 +513,26 @@ def read_record(record): def download_dastcom5(): """Downloads DASTCOM5 database. - Downloads and unzip DASTCOM5 file in default poliastro path (~/.poliastro). + Downloads and unzip DASTCOM5 file in default sbpy path (~/.sbpy). """ - dastcom5_dir = os.path.join(POLIASTRO_LOCAL_PATH, "dastcom5") - dastcom5_zip_path = os.path.join(POLIASTRO_LOCAL_PATH, "dastcom5.zip") + dastcom5_dir = os.path.join(SBPY_LOCAL_PATH, "dastcom5") + dastcom5_zip_path = os.path.join(SBPY_LOCAL_PATH, "dastcom5.zip") if os.path.isdir(dastcom5_dir): raise FileExistsError( "dastcom5 is already created in " + os.path.abspath(dastcom5_dir) ) if not zipfile.is_zipfile(dastcom5_zip_path): - if not os.path.isdir(POLIASTRO_LOCAL_PATH): - os.makedirs(POLIASTRO_LOCAL_PATH) + if not os.path.isdir(SBPY_LOCAL_PATH): + os.makedirs(SBPY_LOCAL_PATH) urllib.request.urlretrieve( FTP_DB_URL + "dastcom5.zip", dastcom5_zip_path, _show_download_progress ) with zipfile.ZipFile(dastcom5_zip_path) as myzip: - myzip.extractall(POLIASTRO_LOCAL_PATH) + myzip.extractall(SBPY_LOCAL_PATH) def _show_download_progress(transferred, block, totalsize): From 33f021f80eef6597686a5fc6bd1113632ac8baaf Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Thu, 28 Feb 2019 17:11:02 +0530 Subject: [PATCH 03/16] Add tests for Dastcom5 module --- sbpy/dastcom5/__init__.py | 2 +- sbpy/dastcom5/tests/__init__.py | 0 sbpy/dastcom5/tests/test_dastcom5.py | 100 +++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 sbpy/dastcom5/tests/__init__.py create mode 100644 sbpy/dastcom5/tests/test_dastcom5.py diff --git a/sbpy/dastcom5/__init__.py b/sbpy/dastcom5/__init__.py index eeee6f0b5..32e058609 100644 --- a/sbpy/dastcom5/__init__.py +++ b/sbpy/dastcom5/__init__.py @@ -4,4 +4,4 @@ All of them are coded as part of SOCIS 2017 proposal for poliastro by Antonio Hidalgo. """ -from sbpy.dastcom5 import dastcom5 +from sbpy.dastcom5.dastcom5 import * diff --git a/sbpy/dastcom5/tests/__init__.py b/sbpy/dastcom5/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sbpy/dastcom5/tests/test_dastcom5.py b/sbpy/dastcom5/tests/test_dastcom5.py new file mode 100644 index 000000000..83c7b065d --- /dev/null +++ b/sbpy/dastcom5/tests/test_dastcom5.py @@ -0,0 +1,100 @@ +import os +from unittest import mock + +import numpy as np +import pytest + +from sbpy import dastcom5 + + +@mock.patch("sbpy.dastcom5.dastcom5.open") +def test_asteroid_db_is_called_with_right_path(mock_open): + dastcom5.asteroid_db() + mock_open.assert_called_with(dastcom5.AST_DB_PATH, "rb") + + +@mock.patch("sbpy.dastcom5.dastcom5.open") +def test_comet_db_is_called_with_right_path(mock_open): + dastcom5.comet_db() + mock_open.assert_called_with(dastcom5.COM_DB_PATH, "rb") + + +@mock.patch("sbpy.dastcom5.dastcom5.open") +def test_read_headers(mock_open): + dastcom5.read_headers() + mock_open.assert_any_call( + os.path.join(dastcom5.DBS_LOCAL_PATH, "dast5_le.dat"), "rb" + ) + mock_open.assert_any_call( + os.path.join(dastcom5.DBS_LOCAL_PATH, "dcom5_le.dat"), "rb" + ) + + +@mock.patch("sbpy.dastcom5.dastcom5.read_headers") +@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") +@mock.patch("sbpy.dastcom5.dastcom5.open") +def test_read_record(mock_open, mock_np_fromfile, mock_read_headers): + mocked_ast_headers = np.array( + [(3184, -1, b"00740473", b"00496815")], + dtype=[ + ("IBIAS1", np.int32), + ("IBIAS0", np.int32), + ("ENDPT2", "|S8"), + ("ENDPT1", "|S8"), + ], + ) + mocked_com_headers = np.array([(99999,)], dtype=[("IBIAS2", " Date: Thu, 28 Feb 2019 17:17:32 +0530 Subject: [PATCH 04/16] Fix PEP8 Errors --- sbpy/dastcom5/__init__.py | 3 ++- sbpy/dastcom5/dastcom5.py | 14 +++++++++----- sbpy/dastcom5/tests/test_dastcom5.py | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sbpy/dastcom5/__init__.py b/sbpy/dastcom5/__init__.py index 32e058609..926f4a333 100644 --- a/sbpy/dastcom5/__init__.py +++ b/sbpy/dastcom5/__init__.py @@ -1,7 +1,8 @@ """Code related to DASTCOM5 service. Functions related to NEOs and different NASA APIs. -All of them are coded as part of SOCIS 2017 proposal for poliastro by Antonio Hidalgo. +All of them are coded as part of SOCIS 2017 proposal +for poliastro by Antonio Hidalgo. """ from sbpy.dastcom5.dastcom5 import * diff --git a/sbpy/dastcom5/dastcom5.py b/sbpy/dastcom5/dastcom5.py index e40710f77..4b64252de 100644 --- a/sbpy/dastcom5/dastcom5.py +++ b/sbpy/dastcom5/dastcom5.py @@ -367,7 +367,8 @@ def orbit_from_record(record): def record_from_name(name): - """Search `dastcom.idx` and return logical records that match a given string. + """Search `dastcom.idx` and return logical records that + match a given string. Body name, SPK-ID, or alternative designations can be used. @@ -494,7 +495,6 @@ def read_record(record): if record <= int(ast_header["ENDPT2"][0].item()): # ENDPT2 indicates end of unnumbered asteroids records if record <= int(ast_header["ENDPT1"][0].item()): - # phis_rec = record_size * (record_number - IBIAS - 1 (header record)) phis_rec = 835 * (record - ast_header["IBIAS0"][0].item() - 1) else: phis_rec = 835 * (record - ast_header["IBIAS1"][0].item() - 1) @@ -529,7 +529,9 @@ def download_dastcom5(): os.makedirs(SBPY_LOCAL_PATH) urllib.request.urlretrieve( - FTP_DB_URL + "dastcom5.zip", dastcom5_zip_path, _show_download_progress + FTP_DB_URL + "dastcom5.zip", + dastcom5_zip_path, + _show_download_progress ) with zipfile.ZipFile(dastcom5_zip_path) as myzip: myzip.extractall(SBPY_LOCAL_PATH) @@ -564,7 +566,8 @@ def entire_db(): ] ) ast_database.rename( - columns={"ASTNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, inplace=True + columns={"ASTNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, + inplace=True ) com_database = pd.DataFrame( com_database[ @@ -574,7 +577,8 @@ def entire_db(): ] ) com_database.rename( - columns={"COMNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, inplace=True + columns={"COMNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, + inplace=True ) df = ast_database.append(com_database, ignore_index=True) df[["NAME", "DESIG", "IREF"]] = df[["NAME", "DESIG", "IREF"]].apply( diff --git a/sbpy/dastcom5/tests/test_dastcom5.py b/sbpy/dastcom5/tests/test_dastcom5.py index 83c7b065d..7ddced43a 100644 --- a/sbpy/dastcom5/tests/test_dastcom5.py +++ b/sbpy/dastcom5/tests/test_dastcom5.py @@ -89,7 +89,9 @@ def test_download_dastcom5_creates_folder( @mock.patch("sbpy.dastcom5.dastcom5.zipfile") @mock.patch("sbpy.dastcom5.dastcom5.os.path.isdir") @mock.patch("sbpy.dastcom5.dastcom5.urllib.request.urlretrieve") -def test_download_dastcom5_downloads_file(mock_request, mock_isdir, mock_zipfile): +def test_download_dastcom5_downloads_file( + mock_request, mock_isdir, mock_zipfile +): mock_isdir.side_effect = lambda x: x == dastcom5.SBPY_LOCAL_PATH mock_zipfile.is_zipfile.return_value = False dastcom5.download_dastcom5() From 1633b938cfe1e385eed16b8d4744a6fb3b0f5a7d Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Thu, 28 Feb 2019 17:25:03 +0530 Subject: [PATCH 05/16] Add pandas to requirements --- sbpy/dastcom5/tests/test_dastcom5.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sbpy/dastcom5/tests/test_dastcom5.py b/sbpy/dastcom5/tests/test_dastcom5.py index 7ddced43a..d5cf58851 100644 --- a/sbpy/dastcom5/tests/test_dastcom5.py +++ b/sbpy/dastcom5/tests/test_dastcom5.py @@ -7,20 +7,23 @@ from sbpy import dastcom5 +@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") @mock.patch("sbpy.dastcom5.dastcom5.open") -def test_asteroid_db_is_called_with_right_path(mock_open): +def test_asteroid_db_is_called_with_right_path(mock_open, mock_np_fromfile): dastcom5.asteroid_db() mock_open.assert_called_with(dastcom5.AST_DB_PATH, "rb") +@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") @mock.patch("sbpy.dastcom5.dastcom5.open") -def test_comet_db_is_called_with_right_path(mock_open): +def test_comet_db_is_called_with_right_path(mock_open, mock_np_fromfile): dastcom5.comet_db() mock_open.assert_called_with(dastcom5.COM_DB_PATH, "rb") +@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") @mock.patch("sbpy.dastcom5.dastcom5.open") -def test_read_headers(mock_open): +def test_read_headers(mock_open, mock_np_fromfile): dastcom5.read_headers() mock_open.assert_any_call( os.path.join(dastcom5.DBS_LOCAL_PATH, "dast5_le.dat"), "rb" @@ -97,6 +100,6 @@ def test_download_dastcom5_downloads_file( dastcom5.download_dastcom5() mock_request.assert_called_once_with( dastcom5.FTP_DB_URL + "dastcom5.zip", - os.path.join(dastcom5.SBPY_LOCAL_PATH, "dastcom5.zip"), + os.path.join(dastcom5.POLIASTRO_LOCAL_PATH, "dastcom5.zip"), dastcom5._show_download_progress, ) From de206d109b947d93f8785bbdcec02891e88ebf31 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Thu, 28 Feb 2019 18:16:38 +0530 Subject: [PATCH 06/16] Fix show download progress --- sbpy/dastcom5/dastcom5.py | 4 ++-- sbpy/dastcom5/tests/test_dastcom5.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sbpy/dastcom5/dastcom5.py b/sbpy/dastcom5/dastcom5.py index 4b64252de..136c6b4f0 100644 --- a/sbpy/dastcom5/dastcom5.py +++ b/sbpy/dastcom5/dastcom5.py @@ -531,13 +531,13 @@ def download_dastcom5(): urllib.request.urlretrieve( FTP_DB_URL + "dastcom5.zip", dastcom5_zip_path, - _show_download_progress + show_download_progress ) with zipfile.ZipFile(dastcom5_zip_path) as myzip: myzip.extractall(SBPY_LOCAL_PATH) -def _show_download_progress(transferred, block, totalsize): +def show_download_progress(transferred, block, totalsize): trans_mb = transferred * block / (1024 * 1024) total_mb = totalsize / (1024 * 1024) print("%.2f MB / %.2f MB" % (trans_mb, total_mb), end="\r", flush=True) diff --git a/sbpy/dastcom5/tests/test_dastcom5.py b/sbpy/dastcom5/tests/test_dastcom5.py index d5cf58851..848285998 100644 --- a/sbpy/dastcom5/tests/test_dastcom5.py +++ b/sbpy/dastcom5/tests/test_dastcom5.py @@ -100,6 +100,6 @@ def test_download_dastcom5_downloads_file( dastcom5.download_dastcom5() mock_request.assert_called_once_with( dastcom5.FTP_DB_URL + "dastcom5.zip", - os.path.join(dastcom5.POLIASTRO_LOCAL_PATH, "dastcom5.zip"), - dastcom5._show_download_progress, + os.path.join(dastcom5.SBPY_LOCAL_PATH, "dastcom5.zip"), + dastcom5.show_download_progress, ) From 005293d86ff6b9783ae62096363d80fc57d190d9 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Sat, 2 Mar 2019 19:15:24 +0530 Subject: [PATCH 07/16] Add Dastcom to utils --- sbpy/dastcom5/README.txt | 1227 ----------------- sbpy/dastcom5/__init__.py | 8 - sbpy/data/utils/__init__.py | 6 + sbpy/{dastcom5 => data/utils}/dastcom5.py | 33 +- .../utils}/tests/__init__.py | 0 .../utils}/tests/test_dastcom5.py | 42 +- 6 files changed, 41 insertions(+), 1275 deletions(-) delete mode 100644 sbpy/dastcom5/README.txt delete mode 100644 sbpy/dastcom5/__init__.py create mode 100644 sbpy/data/utils/__init__.py rename sbpy/{dastcom5 => data/utils}/dastcom5.py (95%) rename sbpy/{dastcom5 => data/utils}/tests/__init__.py (100%) rename sbpy/{dastcom5 => data/utils}/tests/test_dastcom5.py (70%) diff --git a/sbpy/dastcom5/README.txt b/sbpy/dastcom5/README.txt deleted file mode 100644 index c8a159de8..000000000 --- a/sbpy/dastcom5/README.txt +++ /dev/null @@ -1,1227 +0,0 @@ -2014-Aug-18 DASTCOM5 - USER QUICK START - - CONTENTS - - BACKGROUND - - DISTRIBUTION RETRIEVAL - - USAGE - Building software and library - Running DXLOOK - Using the FORTRAN reader library - Example 1: Open DASTCOM5, return all information in a record - Example 2: Open DASTCOM5, return only DASTCOM3 information - Example 3: Open DASTCOM5, return only DASTCOM3 data in legacy D3READ order - Example 4: Open legacy DASTCOM3, return data in legacy D3READ order - - PROGRAMMER NOTES - Overview of database structure - DAST5 - DCOM5 - ADDRESSING - SCANNING THE DATABASE - INDEX FILE - Alternative access methods - - CONTENTS OF DASTCOM5 - - DASTCOM5 BYTE MAP - - CONTACT - - -BACKGROUND - - DASTCOM5 is a direct-access binary database. It contains heliocentric - ecliptic osculating elements for the known asteroids and comets, at single - instants, determined by a least-squares orbit solution fit to optical and - radar astrometric measurements. - - Additional physical, dynamical, and covariance parameters are included when - known. A total of 142 parameters per object are defined within DASTCOM5 - though many may not yet be assigned values, being undetermined. See the - "./dastcom5/src/curdef.inc" file for detailed information on the defined - fields, after retrieving and unzipping the distribution file described below. - - This information is suitable for initializing numerical integrators, assessing - orbit geometry, computing trajectory uncertainties, visual magnitude and, to - some extent, summarizing physical characterization of the body. It is the - database used by the JPL Horizons ephemeris system. - - Each asteroid has one data record containing the most recent information for - that object. Comets, however, may have multiple records, reflecting solutions - at different apparitions. This is because acceleration due to non-gravitational - out-gassing can vary during different perihelion passages and be discernable - from the measurement data. Unless doing historical research, the record for - a comets' apparition closest to the present is typically most relevant. - - DASTCOM5 is a portable, subset product exported from a larger MySQL-based - relational master database called SBDB ("Small-Body Database") maintained at - the NASA/Jet Propulsion Laboratory. - - The DASTCOM5 distribution file archive is updated when necessary to include - newly discovered objects or orbit solution updates derived from newly reported - measurements. Database updates typically occur a couple times per day, but - potentially as frequently as once per hour. They are placed on the public - FTP site of JPL's Solar System Dynamics Group (below). - - The DASTCOM5 distribution .zip file archive contains the following: - - * two binary database files (one holding asteroid data, the second holding - comet data), - - * a plain-text index (linking all objects to their DASTCOM5 record, - permitting look-up based on name, designation, SPK ID, packed MPC - designation, and historical aliases), - - * documentation, - - * latest database reader source code (FORTRAN). The software has been - tested using GFORTRAN (gfortran), Lahey (lf95), Intel (ifort), and - SunStudio (f95) compilers in both 32 and 64-bit builds, under RedHat - Linux 4/5/6. - - The legacy DASTCOM3 file, in use over the last 20+ years (without an official - reader routine), will continue to be produced by conversion indefinately, - using DASTCOM5 as a source and discarding and reorganizing data into the - old structure. - - However, DASTCOM3 cannot contain more than 999,999 object records and so - cannot be produced after that number of objects are cataloged. At the time of - this writing, there are ~624,000 small-body records. While it is likely - discoveries won't approach the DASTCOM3 limit for more than three years, it - is recommended users switch to DASTCOM5 well before that time. Note that - DASTCOM3 does not provide enough information to properly initialize modern - trajectory propagations for some objects having non-gravitational dynamics - (primarily comets with A3 parameters), and has therefore been obsolete for - that purpose for several years. - - DASTCOM4 was an extension to DASTCOM3, defined in 2001, and primarily used - internally at JPL. - - The outline below assumes UNIX/Linux/Mac command line functionality, but - should be adaptable to PC/Windows environments. - - -DISTRIBUTION RETRIEVAL: - - 1. Retrieve the latest database distribution by anonymous FTP from the - JPL Solar System Dynamics server: - - From command-line - - wget ftp://ssd.jpl.nasa.gov/pub/xfr/dastcom5.zip - - OR browser URL bar - - ftp://ssd.jpl.nasa.gov/pub/xfr/dastcom5.zip - - OR command-line FTP login - - ftp ssd.jpl.nasa.gov - Name: anonymous - Password: {your email address} - cd pub/xfr - binary - get dastcom5.zip - exit - - IMPORTANT NOTE: - The database could be updated at any moment within the interval 30-32 - minutes after any hour. Make sure your retrieval is not occurring during - this time to avoid creating a local database on your system potentially - corrupted due to the remote source file being almost instantly rewritten - with an update while your slower Internet transfer is in progress. - - 2. Unzip the archived directory structure - - unzip -ao dastcom5.zip - - The "-ao" options instruct unzip to convert text files to local forms - and over-write any existing files of the same name. - - A directory called "dastcom5" will be created in the current working - directory, along with five sub-directories: - - ./dastcom5/dat - /dast5_le.dat (binary asteroid data) - /dcom5_le.dat (binary comet data) - /dastcom.idx (plain-text database index) - /doc - /README.txt - /news.txt - /dastcom5.map - /src (FORTRAN source for libraries & apps) - /*.f - /*.inc - /Makefile - /dxlook.inp - /exe (initially empty) - /lib (initially empty) - - The /dat sub-directory contains the latest matched-set of databases. - - The database files can be moved and renamed, but the rest of this - discussion assumes the directory structure above for the purpose of - example. - - Note that the three database files in a distribution make up a "matched - set" and MUST be replaced/updated together. If an old 'dast5' is used with - a more recent 'dcom5' (or index), errors may result, including retrieval - of a different object than expected. - - Changes to the distribution or other developments will be noted in the - file './dastcom5/doc/news.txt' - -USAGE - - It is recommended the reader library and applications in the './dastcom5/src' - directory be used to read the database. Advantages include: - - - Binary-independent readability across IEEE platforms. It is not necessary - to have a version of the DASTCOM database that is binary-compatible with - your computer; the reader software translates as necessary. - - - Legacy database compatibility; transparently supports prior DASTCOM3 and - DASTCOM4 databases, and the old limited-release D3READ reader subroutine, - simplifying transition to the new database. - - - Transparent updates: if DASTCOM5 is altered in the future to include - additional information, user software need only be relinked with the - latest libraries from the distribution to read the new database - structure. Calling arguments and user software won't need to change -- - unless the user wants to use the new information. - - - Automatic management of asteroid & comet databases ... software merge of - the two database components is managed in the readers such that both can - be simultaneously and transparently accessed. - - - Error checking - - Since the reader software is configurable with respect to what data it returns, - it should be possible to duplicate the output of legacy readers users may have - for DASTCOM3, reducing the required changes in user code and more rapidly - eliminating the need for DASTCOM3. - - If the provided subroutines are not compatible with user application code, the - provided "dxlook" tool might be used to retrieve data in a shell or scripted - environment. Relevant details are also provided later for implementation of a - reader in other languages. The structure of the database records is summarized - in the text file './dastcom5/doc/dastcom5.map'. - - - Building Software and Library - ----------------------------- - - To build the 'dxlook' command-line application, and the library 'libdxread.a' - used to link with user application software, move to the source directory, - edit the Makefile to set the desired compiler and link flags, then execute a - "make all" command. On a Unix/Linux/Mac platform: - - 1. cd dastcom5/src - - 2. vi Makefile - - - The 'LIBDXREAD' and 'EXEDXREAD' variables can be altered to point to - a different destination for the library archive and executables, if - desired. - - - 'BITDXREAD' can be altered as necesary to select which memory model - (32 or 64-bit) is required for compatibility with user applications. - Options are '-m32' or '-m64' - - - Example settings for four FORTRAN compilers are shown (FC and FFLAGS - variables). It may be possible to simply alter comment-markers to - select the desired compiler. If not, create new FC and FFLAGS as - needed. - - - Once Makefile is customized for the local system, it can be renamed - 'makefile' (lower-case). This will prevent it from being - over-written during future releases while giving local changes - execution precedence over the default distribution 'Makefile' - (upper-case). However, keep an eye on "news.txt" in case an - additional program or subroutine is added to the distribution, and - the distribution Makefile is changed to include it. - - 3. make all - - This will build 'libdxread.a', created as '../lib/libdxread.a' - - Application program 'dxlook' will be created as '../exe/dxlook', - along with some other example programs in the same directory - - User applications would then link with 'libdxread.a' after - compilation to gain access to the database subroutines. - - The library and executable files can be relocated and renamed, though the rest - of this discussion assumes the above basic directory structure for the purpose - of example. - - - Running dxlook - -------------- - - 'dxlook' is a stand-alone command-line tool to rapidly examine DASTCOM - database records. It can also be used to examine legacy databases such as - DASTCOM3 and DASTCOM4. - - Type '../exe/dxlook' from the command-line to execute the program, assuming - the users' working directory location of './dastcom5/src' is unchanged. - - Type 'help' at the 'dxlook>' prompt to list commands. - - To view small-body data, enter a record number or, if the Unix/Linux/Mac - egrep utility is in your path, an asteroid name or designation. - - Type 'x' to exit the 'dxlook' program. - - Program directives are: - - Directive Meaning - ------------------ ----------------------------------------------------- - DB [path/file] Open specified database(s); DASTCOM 3-5 are supported - SUMM Summarize currently opened databases - INDEX [path/file] Specify optional ASCII index file for look-ups - FIELDS [list] Set field codes to display (default= -5, all DASTCOM5) - PAGER {path} Toggle output pager w/executable path (default= none) - LABEL [ON/OFF] Toggle display of field labels (default= ON) - HELP Display this list of directives (same as "?") - {Object} Display {object}; record #, name, designation, SPK ID - !{X} Pass {X} to operating system as a command - X Exit program; same as CLOSE, QUIT, EXIT - - 'dxlook' is controlled by an input file, keyboard, or combination of the two. - - It is recommended that set-up information which doesn't change, such as the - paths to the latest database files, be placed in an input file called - "./dxlook.inp". - - When 'dxlook' is run, it will first look for a file called 'dxlook.inp' in - the run-time directory, load anything there if found, then drop into keyboard - input, which would typically be specific user-queries of the database. - - This is what happened during the test above, using an example directive file - in the current working 'src' directory, './dastcom5/src/dxlook.inp' - - Create another customized dxlook directive file './dxlook.inp' in the - original top-level unzip directory ('cd ../..') containing the lines between - the '---' marks: - - --- - DB ./dastcom5/dat/dast5_le.dat - DB ./dastcom5/dat/dcom5_le.dat - INDEX ./dastcom5/dat/dastcom.idx - PAGER /bin/usr/less - --- - - "PAGER" can be set as needed to point to a preferred text paging program on - the local system. - - Now execute './dastcom5/exe/dxlook'. Type 'summ' at the prompt to summarize - the databases now open. Type "1" to look-up the object in record #1, "99942" - for the object in record 99942, and so on. - - While the default behavior is to display all defined DASTCOM fields, the - FIELDS directive can be used to request 'dxlook' display only select data. - For example, the directive ... - - FIELDS 14,11,802,807,808,809,804,805,806 - - ... requests display of only object name (14), designation (11), calendar - epoch (802), and orbital elements EC, A, QR, W, OM, IN. - - See the './dastcom5/src/curdef.inc' file for a list of all available fields - and their numeric codes. - - Some macros are also defined: - - 'FIELDS -3' requests legacy DASTCOM3 fields only, - 'FIELDS -4' requests legacy DASTCOM4 fields only, - 'FIELDS -5' restores the default, which is "all DASTCOM5 fields" - - Note that numeric data is always displayed first, followed by character data, - regardless of the order you specify with FIELDS. However, the order specified - within those two categories (numeric and character) is maintained for display. - - If the Unix/Linux/Mac 'egrep' command is in your path (type '!which egrep' in - 'dxlook' to determine if it can be found), and INDEX is defined, it will be - possible to look up objects based on their names, SPK IDs, designations, and - other aliases, including regular expressions. - - If there are multiple matches from such a search, select the desired object - using the unique DASTCOM record number on the left-most part of each index - line in the list of matches. - - If 'egrep' is not available in your path, only record numbers may be used - to do look-ups. - - - Using the FORTRAN Reader Library - -------------------------------- - - The principle behind usage of the reader library is to provide a list of data - to be retrieved during future calls to the reader. Each field in an asteroid or - comet record has a code number, as shown in file './dastcom5/src/curdef.inc'. - - The code for each desired field should be placed in an array in the order in - which they are to be returned. This output-request 'map' is then consulted for - each database read and used to determine what information is to be returned - from the read, and in what order. - - There are two primary subroutine calls for programmatic users, DXINI and - DXREAD, with several other special-purpose utility routines. - - DXINI initializes the reader package; the user specifies the database files - to use and the list of desired information and order in which to return it. - - DXREAD then retrieves one small-body data record, returning the requested - data in the specified order from the set-up call previously made to DXINI. - - See './dastcom5/src/dxread.f' comments for a list of all subroutines, details - of their calling arguments and specific discussion of how to use them. - - Some macro field codes ("-3","-4","-5") are available that emulate the return - of the old D3READ subroutine for DASTCOM3 and DASTCOM4. They can be used if - necessary for a "quick and dirty" inclusion of DASTCOM5, by those previously - using D3READ and wanting to minimize changes to their existing software, but - are not recommmended for general use. - - The obsolete D3READ subroutine they emulate returned different data in the - same array slots depending on whether the object was a comet or asteroid. - - If upgrading to DASTCOM5, it would be better to develop a list of every piece - of information needed for both comets and asteroids and put them in the - request list. The information will therefore be returned in the same position - whether the record is for an asteroid or a comet. Fields not defined for a - particular type of object will be returned as zero or blank, but the position - of the data won't change using this approach. - - The following are only four general examples, most relevant to legacy DASTCOM3 - users transitioning to DASTCOM5. Once the basic framework is in place - (example #1), minor variations allow adapting to a variety of other purposes - (examples #2-4). - - Example 1: Open DASTCOM5 and return all information in record (nominal case) - --------- -C -C** Parameterize array dimensions for convenience. Might instead use -C "INCLUDE dxparms.inc" and package NUMNS and NUMCH parameters for -C better future-proofing -C - INTEGER NUMNS0, NUMCH0 - PARAMETER( NUMNS0= 142) ! Max.# of numeric fields to be retrieved - PARAMETER( NUMCH0= 14) ! Max.# of character fields to be retrieved -C -C** Declare necessary variables for DXINI - CHARACTER*1 DBNAM(2)*256 - INTEGER IR8ORD(NUMNS0), ICHORD(NUMCH0), NR8, NCH, ISTAT - LOGICAL BUF, WARN -C -C** Declare necessary variables for DXREAD - CHARACTER*1 CHOUT5(NUMCH0)*80, CHOUT3*217, CERRMS*340 - INTEGER IOBJ, IZONE, LSRC, LERR - REAL*8 R8OUT(NUMNS0) -C -C** Declare local variables - INTEGER I -C -C** Initialization settings - DATA DBNAM / - & './dastcom5/dat/dast5_le.dat', ! Database #1 - & './dastcom5/dat/dcom5_le.dat' / ! Database #2 - DATA IR8ORD / -5,141*0 / ! Macro specifying all DASTCOM5 fields - DATA ICHORD / 14*0 / ! Requested character fields - DATA NR8,NCH / 142, 14 / ! Max. # of num. & char. fields to get - DATA BUF,WARN / .F., .F. / ! Normal values -C -C** Initialize DASTCOM reader package - CALL DXINI( DBNAM, IR8ORD, NR8, ICHORD, NCH, BUF, WARN, ISTAT ) -C -C** Check initialization return status - IF ( ISTAT .NE. 0 ) THEN - PRINT *,'Error on DXINI, ISTAT= ', ISTAT - CALL DXERR( CERRMS, LERR ) - PRINT *,CERRMS(1:LERR) - STOP - ELSE - PRINT *,'Nominal initialization' - END IF - -C** Set IOBJ for the desired objects' logical record & retrieve data - IOBJ= 4 ! Numbered asteroid Vesta - CALL DXREAD( IOBJ, IZONE, LSRC, R8OUT, CHOUT5, ISTAT ) -C -C** Check return status and display data - IF ( ISTAT .NE. 0 ) THEN - PRINT *,'Error on DXREAD(), ISTAT= ', ISTAT - CALL DXERR( CERRMS, LERR ) - PRINT *,CERRMS(1:LERR) - STOP - ELSE - PRINT *,'IZONE= ',IZONE ! Database zone of logical record IOBJ - PRINT *,'LSRC = ',LSRC ! Length of SRC vector - DO I= 1, NR8 ! Objects' numeric data, ordered by IR8ORD() - PRINT *,' R8OUT(',I,')= ',R8OUT(I) - END DO - IF ( NCH .GT. 1 ) THEN ! DASTCOM5 character array - DO I= 1, NCH ! Objects' character data, order by ICHORD() - PRINT *,' CHOUT5(',I,')= ',CHOUT5(I) - END DO - ELSE - PRINT *,' CHOUT3= ',CHOUT3 ! Legacy character block - END IF - END IF - - Depending on how elaborate user software for accessing DASTCOM is, users may - want to formally INCLUDE ./dastcom5/src/dxparms.inc in application programs - that use DXREAD(), and use the parameterized NUMNS and NUMCH values to enhance - compatibility with any future release. - - However, if the application will only ever use DASTCOM in one way, and - will not be concerned with future data that may or may not be added, this - generalization is not necessary. Further, if only a limited number of - fields are of interest, smaller dimensions can be specified, as per DXREAD - and DXINI documentation. - - - Example 2: Open DASTCOM5, return only DASTCOM3 [asteroid] information (subset) - --------- - - Replace three corresponding lines in nominal example #1 above with: - - DATA IR8ORD / ! Request DASTCOM3 asteroid num. fields - & 201,801,802,803,804,805,806,807,808,810, - & 811,809,432,433,401,402,439,431,438, 123*0 / - DATA ICHORD / ! Request DASTCOM3 asteroid char fields - & 14,1,13,11,4,6,7,8,3,5*0 / - DATA NR8,NCH / 19, 9 / ! Max. # num. & char. fields to get - - To generalize and support potential cometary data return for this case, one - could define alternate IR8ORD and ICHORD arrays for DASTCOM3 comet records, - then test whether object is comet or asteroid and re-initialize with DXCLOS - and DXINI calls to use the type-specific list. - - Even better (2b): define a single list that includes all DASTCOM3 asteroid and - comet fields. This avoids having to test what the object is and reinitialize - with a new list. - - DATA IR8ORD / ! Request DASTCOM3 ast+com num. fields - & 201,801,802,803,804,805,806,807,808,810, - & 811,809,432,433, - & 401,402,439,431,438, ! asteroid unique data - & 408,409,403,404,151,118*0/ ! stick comet-unique data at end - DATA ICHORD / ! Request DASTCOM3 ast+com char fields - & 14,1,13,11,4,6,7,8,3, - & 9,10, 2*0 / ! stick comet unique data at end - DATA NR8,NCH / 24, 11 / ! Max. # num. & char. fields to get - - - - Example 3: Open DASTCOM5, return only DASTCOM3 data in legacy D3READ order - --------- - - Replace three corresponding lines in nominal example #1 above with: - - DATA IR8ORD / -3,141*0 / ! Macro specifying only DASTCOM3 fields - . - DATA NR8,NCH / 18, 1 / ! Max. # num. & char. fields to get - . - CALL DXREAD( IOBJ, IZONE, LSRC, R8OUT, CHOUT3, ISTAT ) - - - - Example 4: Open legacy DASTCOM3, return data in legacy subroutine D3READ order - --------- - - Replace corresponding lines in nominal example #1 above with: - - DATA DBNAM / - & '/home/user/data/DASTCOM3' !Legacy database (change pointer) - & ' ' / - DATA IR8ORD / -3,141*0 / ! Macro specifying only DASTCOM3 fields - . - DATA NR8,NCH / 18, 1 / ! Max. # num. & char. fields to get - . - CALL DXREAD( IOBJ, IZONE, LSRC, R8OUT, CHOUT3, ISTAT ) - - -PROGRAMMER NOTES - - Overview of Database Structure - ------------------------------ - - Unlike legacy DASTCOM3 and DASTCOM4 databases, DASTCOM5 is provided as two - files; "dast5" contains numbered and unnumbered asteroids, while "dcom5" - contains comet records. - - Division into two files for asteroids and comets is done because the two types - of bodies contain different information. Comet records are fewer but contain - more potential data fields and so are individually larger than the much more - numerous asteroid records. - - Since a direct access file has one fixed record size, it is advantageous to use - two separate files for asteroids and comets, each with a different fixed record - size mediated in software. This avoids having total physical database size - driven by the few comets with larger records and reduces empty storage space as - the number of cataloged asteroids having records smaller than comets grows. - - As a result, while the total physical size of DASTCOM5 is about twice that of - DASTCOM3, it can store about seven times as much data. - - Both files contain a header record as physical record #1. These header - records include structural information that permits finding objects within - the file. - - - DAST5 - ----- - - 'dast5' contains two groups of objects: all the numbered asteroids followed - by all the unnumbered asteroids. - - 'Numbered asteroids' are those sequentially assigned a number by the IAU - Minor Planet Center, as measurements accumulate and knowledge of their orbit - becomes robust. - - 'Unnumbered asteroids' have less well-determined orbits, and are typically - more recently discovered. Once enough information is available for an - unnumbered asteroid to secure its orbit solution, it is numbered, and - relocated in the database to the numbered zone. - - Consequently, only numbered asteroid record numbers are fixed. All other - record numbers can shift as objects are moved around the database, thus the - need for an index to support look-ups. - - Record "byte" maps showing the specific content of header, asteroid, and comet - records are in the file './dastcom5/doc/dastcom5.map'. - - The 'dast5' file overall structure map is shown below, where BIAS() is as - returned by a call to DXBND: - - physical logical - record ---------------------- record - 1 Header (record #1) - ---------------------- --------------------_ - 1-BIAS(1) Numbered asteroid 1 1 | - 2-BIAS(1) Numbered asteroid 2 2 | - . | Zone 1 - . | (numbered ast.) - N-BIAS(1) Numbered asteroid N N _| - . _ - N-BIAS(1)+1 Unnumbered asteroid #1 N-BIAS(1)+1+BIAS(2) | - N-BIAS(1)+2 Unnumbered asteroid #2 N-BIAS(1)+2+BIAS(2) | - . | Zone 2 - . | (unnumbered ast.) - N-BIAS(1)+X Unnumbered asteroid #X N-BIAS(1)+X+BIAS(2) _| - - - DCOM5 - ----- - - The 'dcom5' overall file structure map is simpler and looks like this: - - physical logical - record ---------------------- record - 1 Header (record #1) - ---------------------- --------------------_ - 2 Comet record #1 2+BIAS(3) | - 3 Comet record #2 3+BIAS(3) | - . | Zone 3 (comets) - . | - Y+1 Comet record #Y Y+1+BIAS(3) _| - - - ADDRESSING - ---------- - - Considering the level of database flux, with objects being added and moved - around daily, the databases and DXREAD library package are organized to use - "logical record" addressing to look up objects. This offers some flexibility. - - The relationship between physical database record numbers and the logical - record numbers users pass to DXREAD to retrieve those records is ... - - physical_record = logical_record - bias_for_zone - - The bias pointer for each zone is given in the header, while the index file - provides each objects' logical record number. The above relationship then - permits calculation of the object's physical record, which can then be - directly read. - - This makes it possible for users to request IAU numbered object 1 (Ceres), for - example, by simply passing IOBJ= 1 to DXREAD(), even though the data is not - physically located in record 1. The reader software can relate that input to - the physical database given the structural information in the header. - - For unnumbered asteroids and comets, the logical address approach allows data - to be relocated as necessary for database maintenance while reducing the - apparent movement of records visible to users. - - - SCANNING THE DATABASE - --------------------- - - Header records also report the logical record boundaries for the categories of - objects. This information can be used, for example, to perform a sequential - search of the entire database as follows: - - Call DXINI to initialize, then call DXBND to retrieve the logical record - bounds (and bias pointers) for each category of object. Proceed to read each - record in sequence, calling DXREAD as IOBJ is incremented positively from - BND(4) to BND(1) for numbered asterods, BND(5) to BND(2) for unnumbered - asteroids, and from BND(6) to BND(3) for comets. - - - INDEX FILE - ---------- - - The index file './dastcom5/dat/dastcom.idx' is part of the "matched set" of - databases and corresponds to the 'dast5' and 'dcom5' of the same distribution - archive. The index is also valid for a legacy DASTCOM3 or DASTCOM4 database - corresponding to the same DASTCOM5 files. - - The index is a plain-text ASCII file suitable for pattern matching using one - of the 'grep' family of tools under Unix/Linux/Mac. - - An example index entry line (between the '----' markers): - ----- -751439 2013 LT14 ,3640966,2013 LT14,2010 NY13,3536865,K13L14T, ----- - - From left to right: - - 1: DASTCOM logical record number -- the value to pass to DXREAD() as IOBJ - (potentially up to an 8 digit integer, for DASTCOM5) - - 2: Space - - 3: Name followed by a comma (alternatively, primary designation, if not named) - - 4: Primary SPK ID number followed by a comma - - 5: Primary designation followed by a comma - - 6: Variable length list of historical or alternate designations - and SPK IDs (from when it was an unnumbered asteroid, for example) - - 7: Final item on the line is an MPC packed designation - - If developing a parsing routine for the index, robustness requires keeping - the length of each item flexible and using the space or comma delimiters as - bounds. In the future, names may grow longer, record and SPK-ID range may - change, etc. - - - Alternative Access Methods - -------------------------- - - It is strongly recommended the provided readers be used. However, if this is - not possible due to a particular language requirement or production - environment ... - - 1. Note that 'dxlook' (perhaps with directive "LABELS off") could be used in - an interpreted script or shell environment to do the database interaction, - with the output being loaded into script variables. - - 2. The databases themselves are not FORTRAN specific, but can be read using - any language that can load a byte-pattern into a properly typed variable - (Perl, etc.). Consult the byte map in './dastcom5/doc/dastcom5.map' to - determine the size and arrangement of each variable in header, asteroid, - and comet records, and have at it. Comments in the FORTRAN code may help. - - The database records consist of 1-byte, 2-byte, and 4-byte integers, - 4-byte and 8-byte floating point reals, and character data-types - (1-byte sequences). - - The nominal distribution files 'dast5_le.dat' and 'dcom5_le.dat' are - little-endian. Therefore, for multi-byte patterns, the first byte is - smallest. - - The provided readers automatically translate on big-endian systems, but - this would have to be handled by user-developed readers on big-endian - systems. However, some of those architectures (generally RISC-based) or - compilers (Intel FORTRAN, for example) may offer switchable endianness. - - -CONTENTS OF DASTCOM5 - - The following is excerpted from '../src/curdef.inc', which will always be -the definitive listing: - -C CURDEF.INC (FORTRAN) -C Add definitions to end of lists here if the database is altered to include -C additional parameters, but do not change or delete existing assignments. -C -C Data-fields currently defined and retrievable by calling DXREAD are listed -C below. Not all retrievable fields will be populated with data. -C -C Column "CODE" gives the integer used to request that quantity by its placement -C in the IR8ORD() array passed to DXINI. The requested value will be stored in -C the corresponding position of the R8OUT output array returned by DXREAD. -C -C All numeric data is returned to the user by DXREAD as 8-byte IEEE floating -C point, although the numeric data is physically stored in the database with -C the different byte-level representations indicated below to reduce physical -C storage space. -C -C Symbols in the availability code: -C -C a = field is defined for asteroid records -C c = field is defined for comet records -C 3+= field is defined for DASTCOM3 and later database readers -C 4+= field is defined for DASTCOM4 and later database readers -C 5+= field is defined for DASTCOM5 and later database readers -C -C The classical orbital elements are heliocentric ecliptic. The ecliptic is -C specified by EQUNOX, which should now always be '2000', indicating J2000 -C ecliptic system (IAU76 constants). -C -C To transform from J2000 ecliptic to the original equatorial system used for -C numerical integration (defined by PENAM), use an obliquity angle (epsilon) -C of 84381.448 arcsec. There are slightly different values of epsilon in -C different sets of constants, but this value was used to convert from the -C precise planetary ephemeris equatorial system of PENAM, and so should be -C used to consistently recover the original numerically integrated equatorial -C coordinates. If ecliptic coordinates are to be used directly for high -C precision applications, convert-as-necessary to the intended ecliptic system. -C -C If EQUNOX is instead '1950', an epsilon of 84404.8362512 arc-seconds should -C be used to recover the original integrator equatorial state in the coordinate -C frame of PENAM. -C -C The au->km conversion value for 'au' distance units should be taken from the -C planetary ephemeris indicated by PENAM, along with other constants such -C as mass parameters (GM's). For PENAMs of at least DE430 and later, 1 au is -C 149597870.700 km, by IAU standard. -C -C Time units are in the coordinate time (CT) scale of general relativity, -C defined by the independent variable in the barycentric planetary ephemeris -C equations of motion. This is equivalent to the IAU TDB time-scale. -C -C "1 day" is defined to be 86400 SI seconds. -C -C NOTE #1: non-gravitational parameters A1, A2, A3 are stored in the database -C in units of 10^-8 au/d^2, but returned by this reader package with units of -C au/d^2. Conversion is done in subroutine DXNASGN. This handling is denoted -C in the list below by the "[s:10^-8 au/day^2]" notation, where "s:" denotes -C "stored as". For example, if the database store value of A1 is 1.3453, the -C value of A1 is 1.3453*10^-8 au/day^2, and that will be returned by this -C reader package. A user-developed reader would need to perform the same units -C conversion. -C -C NOTE #2: values are physically stored with minimum appropriate byte-lengths -C in suitable numerical data-types (i.e., integer, floating point), but are -C converted to an array of 8-byte floating-point double-precision values when -C returned to the user by DXREAD(). This can result in additional digits that -C aren't meaningful; for example, when 4-byte floating-point values (seven -C decimal digits) are stored in the 8-byte return array (fifteen decimal -C digits), the eight additional digits can be artifacts of floating point -C representation. Calculations should take this into account and recognize -C the original REAL*4 database values as having at most seven decimal digits -C of precision. -C -C NOTE #3: The non-gravitational A1-A3, DT and related model parameters are as -C described in "Cometary Orbit Determination and Nongravitational Forces", -C D.K. Yeomans, P.W. Chodas, G. Sitarski, S. Szutowicz, M Krolikowska, in -C Comets II, University of Arizona Press (2004), pp. 137-151. -C -C Physically stored values REAL*8 (8-byte IEEE floating precision numeric) -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 801 ac/3+ EPOCH Time of osc. orbital elements solution, JD (CT,TDB) -C 802 ac/3+ CALEPO Time of osc. orbital elements solution, YYYYDDMM.ffff -C 803 ac/3+ MA Mean anomaly at EPOCH, deg (elliptical & hyperbolic cases, -C "9.999999E99" if not available) -C 804 ac/3+ W Argument of periapsis at EPOCH, J2000 ecliptic, deg. -C 805 ac/3+ OM Longitude of ascending node at EPOCH, J2000 ecliptic,deg. -C 806 ac/3+ IN Inclination angle at EPOCH wrt J2000 ecliptic, deg. -C 807 ac/3+ EC Eccentricity at EPOCH -C 808 ac/3+ A Semi-major axis at EPOCH, au -C 809 ac/3+ QR Perihelion distance at EPOCH, au -C 810 ac/3+ TP Perihelion date for QR at EPOCH, JD (CT,TDB) -C 811 ac/3+ TPCAL Perihelion date for QR at EPOCH, format YYYYMMDD.fff -C 812 ac/5+ TPFRAC Decimal (fractional) part of TP for extended precision -C 813 ac/4+ SOLDAT Date orbit solution was performed, JD (CT,TDB) -C -C DERIVED from physically stored REAL*8 (8-byte IEEE floating precision numeric) -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 851 ac/3+ ADIST Aphelion distance at EPOCH, au -C 852 ac/3+ PER Sidereal orbit period @ EPOCH, Julian yr (365.25 d/Jul.yr) -C 853 ac/3+ ANGMOM Specific angular momentum at EPOCH, au^2/D -C 854 ac/3+ N Mean motion, deg/day (elliptical and hyperbolic cases, -C "9.999999E99" if not available) -C 855 ac/3+ DAN Heliocentric distance of ascending node at EPOCH, au -C 856 ac/3+ DDN Heliocentric distance of descending node at EPOCH, au -C 857 ac/3+ L Ecliptic longitude of perihelion at EPOCH, deg. -C 858 ac/3+ B Ecliptic latitude of perihelion at EPOCH, deg. -C -C Physically stored REAL*8 (8-byte IEEE floating precision numeric) -C Requires multiple storage slots -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 899 ac/4+ SRC(01) Square root covariance vector. Vector-stored upper- -C triangular matrix with order {EC,QR,TP,OM,W,IN,{ESTL}}. -C Always reserve enough space (i.e., up to 55 slots) in -C both request and output arrays to hold complete vector. -C -C SRC in matrix form (units are days, radians, au): -C -C EC QR TP OM W IN {ESTL} -C EC e11 e12 e13 e14 e15 e16 -C QR e22 e23 e24 e25 e26 -C TP e33 e34 e35 e36 -C OM e44 e45 e46 -C W e55 e56 -C IN e66 -C {ESTL} -C -C The SRC vector stores the matrix elements from row i and -C column j (i<=j) in vector slot j*(j-1)/2 + i. i.e., upper -C part only, stored by columns: -C -C SRC(1,..)= e11,e12,e22,e13,e23 ... -C -C To obtain a covariance matrix, bottom-fill an SRC matrix -C with zeros to obtain matrix RI. Multiply RI by its -C transpose: -C -C T -C COV = RI * RI -C -C Physically stored values REAL*4 (4-byte IEEE floating precision numeric) -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 401 ac/3+ H Absolute visual magnitude (IAU H-G system) (99=unknown) -C 402 ac/3+ G Mag. slope parm. (IAU H-G)(99=unknown & 0.15 not assumed) -C 403 c/3+ M1 Total absolute magnitude, mag. -C 404 c/3+ M2 Nuclear absolute magnitue, mag. -C 405 c/4+ K1 Total absolute magnitude scaling factor -C 406 c/4+ K2 Nuclear absolute magnitude scaling factor -C 407 c/4+ PHCOF Phase coefficient for K2= 5 -C 408 ac/3+ A1 Non-grav. accel., radial component, [s:10^-8 au/day^2] -C 409 ac/3+ A2 Non-grav. accel., transverse component,[s:10^-8 au/day^2] -C 410 ac/4+ A3 Non-grav. accel., normal component, [s:10^-8 au/day^2] -C 411 c/4+ DT Non-grav. lag/delay parameter, days -C 412 ac/5+ R0 Non-grav. model constant, normalizing distance, au -C 413 ac/5+ ALN Non-grav. model constant, normalizing factor -C 414 ac/5+ NM Non-grav. model constant, exponent m -C 415 ac/5+ NN Non-grav. model constant, exponent n -C 416 ac/5+ NK Non-grav. model constant, exponent k -C 417 c/4+ S0 Center-of-light estimated offset at 1 au, km -C 418 c/5+ TCL Center-of-light start-time offset, d since "ref.time" -C 419 a /5+ LGK Surface thermal conductivity log_10(k), (W/m/K) -C 420 ac/5+ RHO Bulk density, kg/m^3 -C 421 ac/5+ AMRAT Solar pressure model, area/mass ratio, m^2/kg -C 422 c/5+ AJ1 Jet 1 acceleration, au/d^2 -C 423 c/5+ AJ2 Jet 2 acceleration, au/d^2 -C 424 c/5+ ET1 Thrust angle, colatitude of jet 1, deg. -C 425 c/5+ ET2 Thrust angle, colatitude of jet 2, deg. -C 426 c/5+ DTH Jet model diurnal lag angle, deg. (delta_theta) -C 427 ac/5+ ALF Spin pole orientation, RA, deg. -C 428 ac/5+ DEL Spin pole orientation, DEC, deg. -C 429 ac/5+ SPHLM3 Earth gravity sph. harm. model limit, Earth radii -C 430 ac/5+ SPHLM5 Jupiter grav. sph. harm. model limit, Jupiter radii -C 431 ac/3+ RP Object rotational period, hrs -C 432 ac/3+ GM Object mass parameter, km^3/s^2 -C 433 ac/3+ RAD Object mean radius, km -C 434 ac/5+ EXTNT1 Triaxial ellipsoid, axis 1/largest equat. extent, km -C 435 ac/5+ EXTNT2 Triaxial ellipsoid, axis 2/smallest equat. extent, km -C 436 ac/5+ EXTNT3 Triaxial ellipsoid, axis 3/polar extent, km -C 437 ac/4+ MOID Earth MOID at EPOCH time, au; '99' if not computed -C 438 ac/3+ ALBEDO Geometric visual albedo, 99 if unknown -C 439 a /3+ BVCI B-V color index, mag., 99 if unknown -C 440 a /5+ UBCI U-B color index, mag., 99 if unknown -C 441 a /5+ IRCI I-R color index, mag., 99 if unknown -C 442 ac/4+ RMSW RMS of weighted optical residuals, arcsec -C 443 ac/5+ RMSU RMS of unweighted optical residuals, arcsec -C 444 ac/5+ RMSN RMS of normalized optical residuals -C 445 ac/5+ RMSNT RMS of all normalized residuals -C 446 a /5+ RMSH RMS of abs. visual magnitude (H) residuals, mag. -C 447 c/5+ RMSMT RMS of MT estimate residuals, mag. -C 448 c/5+ RMSMN RMS of MN estimate residuals, mag. -C -C Physically stored values INTEGER*4 (4-byte integer numeric) -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 201 ac/3+ NO Logical record-number of this object in DASTCOM -C 202 ac/4+ NOBS Number of observations of all types used in orbit soln. -C 203 ac/4+ OBSFRST Start-date of observations used in fit, YYYYMMDD -C 204 ac/4+ OBSLAST Stop-date of observations used in fit, YYYYMMDD -C -C Physically stored values INTEGER*1 (1-byte signed integers) -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 101 ac/5+ PRELTV Planet relativity "bit-switch" byte: bits 0-7 are set to -C 1 if relativity for corresponding planet was computed, -C 0 if not. For example, if Earth & Jupiter, FORTRAN(95) -C statement IBITS(PRELTV,J,1) should return 1 when J=2 or -C J=4, but zero for every other J through 7. No provision -C for supporting Pluto relativity. -C 102 ac/5+ SPHMX3 Earth grav. model max. degree; 0=point-mass, 2= J2 only, -C 3= up to J3 zonal, 22= 2x2 field, 33=3x3 field, etc. -C 103 ac/5+ SPHMX5 Jupiter grav. max. deg.; 0=point-mass, 2= J2 only, -C 3= up to J3 zonal, 22= 2x2 field, 33=3x3 field, etc. -C 104 ac/5+ JGSEP Galilean satellites used as sep. perturbers; 0=no 1=yes -C 105 ac/5+ TWOBOD Two-body orbit model flag; 0=no 1=yes -C 106 ac/5+ NSATS Number of satellites; 99 if unknown. -C 107 ac/4+ UPARM Orbit condition code; 99 if not computed -C 108 ac/4+ LSRC Length of square-root cov. vector SRC (# elements used) -C -C Physically stored values INTEGER*2 (2-byte integers) -C -C CODE avail Label Definition -C ---- ----- ------- --------------------------------------------------------- -C 151 c/3+ IPYR Perihelion year (i.e., 1976, 2012, 2018, etc.) -C 152 ac/3+ NDEL Number of radar delay measurements used in orbit soln. -C 153 ac/3+ NDOP Number of radar Doppler measurements used in orbit soln. -C 154 c/5+ NOBSMT Number of magnitude measurements used in total mag. soln. -C 155 c/5+ NOBSMN Number of magnitude measurements used in nuc. mag. soln. -C 156 c/3+ COMNUM IAU comet number (parsed from DESIG) -C -C Physically stored character data return in CHOUT argument: -C 'length' is the maximum number of characters in the field -C -C CODE avail length Label Definition -C ---- ----- ------- ------ --------------------------------------------------- -C 001 ac/3+ 4 EQUNOX Equinox of orbital elements ('1950' or '2000') -C 002 ac/4+ 6 PENAM Planetary ephemeris ID/name -C 003 ac/3+ 12 SBNAM Small-body perturber ephemeris ID/name -C 004 a /3 5 SPTYPT Tholen spectral type -C 005 a /4+ 5 SPTYPS SMASS-II spectral type -C 006 ac/3+ 9 DARC Data arc span (year-year, OR integer # of days) -C 007 a /3+ 41 COMNT1 Asteroid comment line #1 -C 008 a /3+ 80 COMNT2 Asteroid comment line #2 -C 009 c/3+ 49 COMNT3 Comet comment line #1 -C 010 c/3+ 80 COMNT4 Comet comment line #2 -C 011 ac/3+ 13 DESIG Object designation -C 012 ac/4+ 14 ESTL Dynamic parameter estimation list. Last symbol set -C to '+' if list is too long for field; check -C object record comments field for full list. -C 013 ac/3+ 10 IREF Solution reference/ID/name -C 014 ac/3+ 29 NAME Object name - - -DASTCOM5 BYTE MAP - - The following is an inclusion of './dastcom5/doc/dastcom5.map', which will - always be the definitive listing: - - DASTCOM5 Binary Record Structure - -Asteroid Header Record : 835 bytes | Comet Header Record : 976 bytes -____________________________________|____________________________________ - Bytes reserved : 86 | Bytes reserved : 82 - Bytes undefined : 749 | Bytes undefined : 894 - | -Name Type Bytes Cumulative | Name Type Bytes Cumulative -------- ------- ------ ---------- | ------- ------- ------ ---------- -IBIAS1 I 4 4 | IBIAS2 I 4 4 -BEGINP C 8*3=24 28 | BEGINP C 8*3=24 28 -ENDPT C 8*3=24 52 | ENDPT C 8*3=24 52 -CALDATE C 19 71 | CALDATE C 19 71 -JDDATE D 8 79 | JDDATE D 8 79 -FTYP C 1 80 | FTYP C 1 80 -BYTE2A I 2 82 | BYTE2C I 2 82 -IBIAS0 I 4 86 | - - 749 835 | - 894 976 -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - NOTES on DASTCOM5 headers - - 1. ENDPT and BEGINP character strings contained the first and last - logical record boundaries for the 3 categories of object: - IAU-numbered asteroids, unnumbered asteroids, and comets. - - Because the database is issued in two files (DAST5 and DCOM5), - comet header BND() is zero-filled for DAST5 and asteroid header - BND() is zero-filled for DCOM5. - - Example: - - DAST5: BEGINP= '000000010050000100000000' - |BND(4)||BND(5)||NOCOMS| - - ENDPT = '003332730075428200000000' - |BND(1)||BND(2)||NOCOMS| - - DCOM5: BEGINP= '000000000000000000900001' - |_NO_ASTEROIDS_||BND(6)| - - ENDPT = '000000000000000000903900' - |_NO_ASTEROIDS_||BND(3)| - - 2. CALDATE is character-format creation date: "YYYY-MM-DD_HH:MM:SS" - JDDATE is Julian astronomical day creation date (REAL*8 numeric) - - 3. IBIAS1 & IBIAS2 and new IBIAS0 - - Since the database is issued in two files (DAST5 and DCOM5), there - is no IBIAS2 field in the DAST5 header and no IBIAS0 or IBIAS1 - fields in the DCOM5 header. - - physical record = user logical record - IBIAS - - 4. For byte #80 of header records (character), - - 'A' denotes DASTCOM3, - 'C' denotes DASTCOM4, - '5' denotes DASTCOM5 - - The database type variations will be detected & handled in reader(s). - - 5. Byte 81-82 of each header is a two-byte integer always set to 26901 - and necessary for database structure tests. - - 6. may be null, character ' ', or anything - -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -Asteroid Record : 835 bytes | Comet Record : 976 bytes -____________________________________|____________________________________ - Bytes reserved : 835 | Bytes reserved : 976 - Bytes undefined: 0 | Bytes undefined: 0 - | -Name Type Bytes Cumulative | Name Type Bytes Cumulative -------- ------- ------ ---------- | ------ ------- ------ ---------- -NO I 4 4 | NO I 4 4 -NOBS I 4 8 | NOBS I 4 8 -OBSFRST I 4 12 | OBSFRST I 4 12 -OBSLAST I 4 16 | OBSLAST I 4 16 -EPOCH D 8 24 | EPOCH D 8 24 -CALEPO D 8 32 | CALEPO D 8 32 -MA D 8 40 | MA D 8 40 -W D 8 48 | W D 8 48 -OM D 8 56 | OM D 8 56 -IN D 8 64 | IN D 8 64 -EC D 8 72 | EC D 8 72 -A D 8 80 | A D 8 80 -QR D 8 88 | QR D 8 88 -TP D 8 96 | TP D 8 96 -TPCAL D 8 104 | TPCAL D 8 104 -TPFRAC D 8 112 | TPFRAC D 8 112 -SOLDAT D 8 120 | SOLDAT D 8 120 -SRC(1-45) D 45*8=360 480 | SRC(1-55) D 55*8= 440 560 -PRELTV I 1 481 | PRELTV I 1 561 -SPHMX3 I 1 482 | SPHMX3 I 1 562 -SPHMX5 I 1 483 | SPHMX5 I 1 563 -JGSEP I 1 484 | JGSEP I 1 564 -TWOBOD I 1 485 | TWOBOD I 1 565 -NSATS I 1 486 | NSATS I 1 566 -UPARM I 1 487 | UPARM I 1 567 -LSRC I 1 488 | LSRC I 1 568 - | IPYR I 2 570 -NDEL I 2 490 | NDEL I 2 572 -NDOP I 2 492 | NDOP I 2 574 - | NOBSMT I 2 576 - | NOBSMN I 2 578 -H R 4 496 | H R 4 582 -G R 4 500 | G R 4 586 - | M1 (MT) R 4 590 - | M2 (MN) R 4 594 - | K1 (MTS) R 4 598 - | K2 (MNS) R 4 602 - | PHCOF (MNP)R 4 606 -A1 R 4 504 | A1 R 4 610 -A2 R 4 508 | A2 R 4 614 -A3 R 4 512 | A3 R 4 618 - | DT R 4 622 -R0 R 4 516 | R0 R 4 626 -ALN R 4 520 | ALN R 4 630 -NM R 4 524 | NM R 4 634 -NN R 4 528 | NN R 4 638 -NK R 4 532 | NK R 4 642 - | S0 R 4 646 - | TCL R 4 650 -LGK R 4 536 | -RHO R 4 540 | RHO R 4 654 -AMRAT R 4 544 | AMRAT R 4 658 - | AJ1 R 4 662 - | AJ2 R 4 666 - | ET1 R 4 670 - | ET2 R 4 674 - | DTH R 4 678 -ALF R 4 548 | ALF R 4 682 -DEL R 4 552 | DEL R 4 686 -SPHLM3 R 4 556 | SPHLM3 R 4 690 -SPHLM5 R 4 560 | SPHLM5 R 4 694 -RP R 4 564 | RP R 4 698 -GM R 4 568 | GM R 4 702 -RAD R 4 572 | RAD R 4 706 -EXTNT1 R 4 576 | EXTNT1 R 4 710 -EXTNT2 R 4 580 | EXTNT2 R 4 714 -EXTNT3 R 4 584 | EXTNT3 R 4 718 -MOID R 4 588 | MOID R 4 722 -ALBEDO R 4 592 | ALBEDO R 4 726 -BVCI R 4 596 | -UBCI R 4 600 | -IRCI R 4 604 | -RMSW R 4 608 | RMSW R 4 730 -RMSU R 4 612 | RMSU R 4 734 -RMSN R 4 616 | RMSN R 4 738 -RMSNT R 4 620 | RMSNT R 4 742 -RMSH R 4 624 | - | RMSMT R 4 746 - | RMSMN R 4 750 -EQUNOX C 4 628 | EQUNOX C 4 754 -PENAM C 6 634 | PENAM C 6 760 -SBNAM C 12 646 | SBNAM C 12 772 -SPTYPT C 5 651 | -SPTYPS C 5 656 | -DARC C 9 665 | DARC C 9 781 -COMNT1 C 41 706 | -COMNT2 C 80 786 | - | COMNT3 C 49 830 - | COMNT2 C 80 910 -DESIG C 13 799 | DESIG C 13 923 -ASTEST C 8 807 | COMEST C 14 937 -IREF C 10 817 | IREF C 10 947 -ASTNAM C 18 835 | COMNAM C 29 976 -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 'D' type denotes floating-point DOUBLE PRECISION (8-byte REAL*8) - 'I' type denotes INTEGER of indicated byte-length (1,2,or 4) - 'R' type denotes floating-point REAL*4 (4-byte) - 'C' type denotes CHARACTER data of indicated length -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -CONTACT - - If any bugs are found, or problems are encountered compiling or using the - FORTRAN code provided, with compiler X on platform Y, let us know: - - e-mail: Jon.D.Giorgini@jpl.nasa.gov - - If you are able to successfully build and link on a different OS with a - different compiler, let us know how it went and what you had to do. Credit - will be given where credit is due. - - This software is primarily intended for our internal use (and we aren't a - programming group) so is being made available "as-is". However, some issues - might readily be resolved if access to compiler X on platform Y is possible. - - Little or no support is available to assist re-implementation outside JPL in - other languages, or resolve problems with significantly altered versions of - the distribution. - -COPYRIGHT - -Copyright 2013, by the California Institute of Technology. ALL RIGHTS RESERVED. -United States Government Sponsorship acknowledged. Any commercial use must be -negotiated with the Office of Technology Transfer at the California Institute -of Technology. - -This software may be subject to U.S. export control laws. By accepting this -software, the user agrees to comply with all applicable U.S. export laws and -regulations. User has the responsibility to obtain export licenses, or other -export authority as may be required before exporting such information to -foreign countries or providing access to foreign persons. diff --git a/sbpy/dastcom5/__init__.py b/sbpy/dastcom5/__init__.py deleted file mode 100644 index 926f4a333..000000000 --- a/sbpy/dastcom5/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Code related to DASTCOM5 service. - -Functions related to NEOs and different NASA APIs. -All of them are coded as part of SOCIS 2017 proposal -for poliastro by Antonio Hidalgo. - -""" -from sbpy.dastcom5.dastcom5 import * diff --git a/sbpy/data/utils/__init__.py b/sbpy/data/utils/__init__.py new file mode 100644 index 000000000..23a0a5dde --- /dev/null +++ b/sbpy/data/utils/__init__.py @@ -0,0 +1,6 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst + +# This sub-module is destined for common non-package specific utility +# functions. + +from sbpy.data.utils import dastcom5 diff --git a/sbpy/dastcom5/dastcom5.py b/sbpy/data/utils/dastcom5.py similarity index 95% rename from sbpy/dastcom5/dastcom5.py rename to sbpy/data/utils/dastcom5.py index 136c6b4f0..fa297a332 100644 --- a/sbpy/dastcom5/dastcom5.py +++ b/sbpy/data/utils/dastcom5.py @@ -1,13 +1,13 @@ import os import re +import shutil import urllib.request import zipfile import astropy.units as u import numpy as np -import pandas as pd from astropy.time import Time -from astropy.table import Table +from astropy.table import Table, vstack import astropy.units as u AST_DTYPE = np.dtype( @@ -330,7 +330,7 @@ def orbit_from_name(name): """ records = record_from_name(name) - orbits = [self.orbit_from_record(rec) for rec in records] + orbits = [orbit_from_record(rec) for rec in records] tbl = Table(orbits) return tbl @@ -510,7 +510,7 @@ def read_record(record): return body_data -def download_dastcom5(): +def download_dastcom5(update=False): """Downloads DASTCOM5 database. Downloads and unzip DASTCOM5 file in default sbpy path (~/.sbpy). @@ -520,10 +520,15 @@ def download_dastcom5(): dastcom5_dir = os.path.join(SBPY_LOCAL_PATH, "dastcom5") dastcom5_zip_path = os.path.join(SBPY_LOCAL_PATH, "dastcom5.zip") - if os.path.isdir(dastcom5_dir): + if os.path.isdir(dastcom5_dir) and not update: raise FileExistsError( "dastcom5 is already created in " + os.path.abspath(dastcom5_dir) ) + + if os.path.isdir(dastcom5_dir) and update: + shutil.rmtree(dastcom5_dir) + + print("Downloading the latest DASTCOM5 Database") if not zipfile.is_zipfile(dastcom5_zip_path): if not os.path.isdir(SBPY_LOCAL_PATH): os.makedirs(SBPY_LOCAL_PATH) @@ -535,6 +540,7 @@ def download_dastcom5(): ) with zipfile.ZipFile(dastcom5_zip_path) as myzip: myzip.extractall(SBPY_LOCAL_PATH) + os.remove(dastcom5_zip_path) def show_download_progress(transferred, block, totalsize): @@ -558,30 +564,19 @@ def entire_db(): ast_database = asteroid_db() com_database = comet_db() - ast_database = pd.DataFrame( + ast_database = Table( ast_database[ list(ast_database.dtype.names[:17]) + list(ast_database.dtype.names[-4:-3]) + list(ast_database.dtype.names[-2:]) ] ) - ast_database.rename( - columns={"ASTNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, - inplace=True - ) - com_database = pd.DataFrame( + com_database = Table( com_database[ list(com_database.dtype.names[:17]) + list(com_database.dtype.names[-4:-3]) + list(com_database.dtype.names[-2:]) ] ) - com_database.rename( - columns={"COMNAM": "NAME", "NO": "NUMBER", "CALEPO": "CALEPOCH"}, - inplace=True - ) - df = ast_database.append(com_database, ignore_index=True) - df[["NAME", "DESIG", "IREF"]] = df[["NAME", "DESIG", "IREF"]].apply( - lambda x: x.str.strip().str.decode("utf-8") - ) + df = vstack(ast_database, com_database) return df diff --git a/sbpy/dastcom5/tests/__init__.py b/sbpy/data/utils/tests/__init__.py similarity index 100% rename from sbpy/dastcom5/tests/__init__.py rename to sbpy/data/utils/tests/__init__.py diff --git a/sbpy/dastcom5/tests/test_dastcom5.py b/sbpy/data/utils/tests/test_dastcom5.py similarity index 70% rename from sbpy/dastcom5/tests/test_dastcom5.py rename to sbpy/data/utils/tests/test_dastcom5.py index 848285998..1e6b8f3c1 100644 --- a/sbpy/dastcom5/tests/test_dastcom5.py +++ b/sbpy/data/utils/tests/test_dastcom5.py @@ -4,25 +4,25 @@ import numpy as np import pytest -from sbpy import dastcom5 +from sbpy.data.utils import dastcom5 -@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") -@mock.patch("sbpy.dastcom5.dastcom5.open") +@mock.patch("sbpy.data.utils.dastcom5.np.fromfile") +@mock.patch("sbpy.data.utils.dastcom5.open") def test_asteroid_db_is_called_with_right_path(mock_open, mock_np_fromfile): dastcom5.asteroid_db() mock_open.assert_called_with(dastcom5.AST_DB_PATH, "rb") -@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") -@mock.patch("sbpy.dastcom5.dastcom5.open") +@mock.patch("sbpy.data.utils.dastcom5.np.fromfile") +@mock.patch("sbpy.data.utils.dastcom5.open") def test_comet_db_is_called_with_right_path(mock_open, mock_np_fromfile): dastcom5.comet_db() mock_open.assert_called_with(dastcom5.COM_DB_PATH, "rb") -@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") -@mock.patch("sbpy.dastcom5.dastcom5.open") +@mock.patch("sbpy.data.utils.dastcom5.np.fromfile") +@mock.patch("sbpy.data.utils.dastcom5.open") def test_read_headers(mock_open, mock_np_fromfile): dastcom5.read_headers() mock_open.assert_any_call( @@ -33,9 +33,9 @@ def test_read_headers(mock_open, mock_np_fromfile): ) -@mock.patch("sbpy.dastcom5.dastcom5.read_headers") -@mock.patch("sbpy.dastcom5.dastcom5.np.fromfile") -@mock.patch("sbpy.dastcom5.dastcom5.open") +@mock.patch("sbpy.data.utils.dastcom5.read_headers") +@mock.patch("sbpy.data.utils.dastcom5.np.fromfile") +@mock.patch("sbpy.data.utils.dastcom5.open") def test_read_record(mock_open, mock_np_fromfile, mock_read_headers): mocked_ast_headers = np.array( [(3184, -1, b"00740473", b"00496815")], @@ -59,10 +59,10 @@ def test_read_record(mock_open, mock_np_fromfile, mock_read_headers): ) -@mock.patch("sbpy.dastcom5.dastcom5.os.makedirs") -@mock.patch("sbpy.dastcom5.dastcom5.zipfile") -@mock.patch("sbpy.dastcom5.dastcom5.os.path.isdir") -@mock.patch("sbpy.dastcom5.dastcom5.urllib.request") +@mock.patch("sbpy.data.utils.dastcom5.os.makedirs") +@mock.patch("sbpy.data.utils.dastcom5.zipfile") +@mock.patch("sbpy.data.utils.dastcom5.os.path.isdir") +@mock.patch("sbpy.data.utils.dastcom5.urllib.request") def test_download_dastcom5_raises_error_when_folder_exists( mock_request, mock_isdir, mock_zipfile, mock_makedirs ): @@ -76,10 +76,10 @@ def test_download_dastcom5_raises_error_when_folder_exists( ) -@mock.patch("sbpy.dastcom5.dastcom5.urllib.request") -@mock.patch("sbpy.dastcom5.dastcom5.os.makedirs") -@mock.patch("sbpy.dastcom5.dastcom5.zipfile") -@mock.patch("sbpy.dastcom5.dastcom5.os.path.isdir") +@mock.patch("sbpy.data.utils.dastcom5.urllib.request") +@mock.patch("sbpy.data.utils.dastcom5.os.makedirs") +@mock.patch("sbpy.data.utils.dastcom5.zipfile") +@mock.patch("sbpy.data.utils.dastcom5.os.path.isdir") def test_download_dastcom5_creates_folder( mock_isdir, mock_zipfile, mock_makedirs, mock_request ): @@ -89,9 +89,9 @@ def test_download_dastcom5_creates_folder( mock_makedirs.assert_called_once_with(dastcom5.SBPY_LOCAL_PATH) -@mock.patch("sbpy.dastcom5.dastcom5.zipfile") -@mock.patch("sbpy.dastcom5.dastcom5.os.path.isdir") -@mock.patch("sbpy.dastcom5.dastcom5.urllib.request.urlretrieve") +@mock.patch("sbpy.data.utils.dastcom5.zipfile") +@mock.patch("sbpy.data.utils.dastcom5.os.path.isdir") +@mock.patch("sbpy.data.utils.dastcom5.urllib.request.urlretrieve") def test_download_dastcom5_downloads_file( mock_request, mock_isdir, mock_zipfile ): From 779e6c3c35cf6c71a06200e07ad07bf7748315aa Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Sat, 9 Mar 2019 04:32:42 +0530 Subject: [PATCH 08/16] Add a wrapper around dastcom5 --- sbpy/data/orbit.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/sbpy/data/orbit.py b/sbpy/data/orbit.py index b1ac72b03..afdeb3635 100644 --- a/sbpy/data/orbit.py +++ b/sbpy/data/orbit.py @@ -17,9 +17,9 @@ import astropy.units as u from warnings import warn -from ..bib import cite -from ..exceptions import SbpyException -from . import conf, DataClass, QueryError, TimeScaleWarning +from .. import bib +from . import conf, DataClass +from .. import utils __all__ = ['Orbit', 'OrbitError', 'OpenOrbError'] @@ -180,6 +180,34 @@ def from_horizons(cls, targetids, id_type='smallbody', return cls.from_table(all_elem) + @classmethod + def from_dastcom5(cls, name): + """Load orbital elements from the DASTCOM5 Database + (ftp://ssd.jpl.nasa.gov/pub/ssd/dastcom5.zip). + + Parameters + ---------- + name: str, mandatory + Name of NEO + + Returns + ------- + `~Orbit` object + + Examples + -------- + >>> from sbpy.data import Orbit + >>> orb = Orbit.from_dastcom5('atira') # doctest: +REMOTE_DATA + >>> orb # doctest: +SKIP + + """ + dastcom5_dir = os.path.join(utils.dastcom5.SBPY_LOCAL_PATH, "dastcom5") + if not os.path.isdir(dastcom5_dir): + utils.dastcom5.download_dastcom5() + + tb = utils.dastcom5.orbit_from_name(name=name) + return cls.from_table(tb) + @classmethod @cite({'data source': 'https://minorplanetcenter.net/iau/MPEph/MPEph.html'}) From e85d6b0b743cd51540080ca33d277865c1b67030 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Sat, 9 Mar 2019 04:47:16 +0530 Subject: [PATCH 09/16] Add text about DASTCOM5 to docs --- docs/sbpy/data/dastcom5.rst | 21 +++++++++++++++++++++ docs/sbpy/data/index.rst | 1 + 2 files changed, 22 insertions(+) create mode 100644 docs/sbpy/data/dastcom5.rst diff --git a/docs/sbpy/data/dastcom5.rst b/docs/sbpy/data/dastcom5.rst new file mode 100644 index 000000000..8ac4ace15 --- /dev/null +++ b/docs/sbpy/data/dastcom5.rst @@ -0,0 +1,21 @@ +============== +Using DASTCOM5 +============== + + +For using the DASTCOM5 Module, you have to first download the databse locally. +That can be done by: + + >>> from sbpy.utils import dastcom5 + >>> dastcom5.download_dastcom5() # doctest: +SKIP + +After the database is downloaded, all the queries can be done easily. + +DASTCOM5 is a subset of Small Body Database provided by JPL, NASA. +For querying the database, either name or record number for the object +can be used. + + >>> dastcom5.orbit_from_name('atira') # doctest: +SKIP + >>> dastcom5.orbit_from_record(900001) # doctest: +SKIP + +More information about the DASTCOM5 Database can be taken from it's README file. diff --git a/docs/sbpy/data/index.rst b/docs/sbpy/data/index.rst index 6af4547e7..dd8406efb 100644 --- a/docs/sbpy/data/index.rst +++ b/docs/sbpy/data/index.rst @@ -26,6 +26,7 @@ Content .. toctree:: :maxdepth: 2 + dastcom5.rst dataclass.rst ephem.rst obs.rst From 61e2b544da263cef5922d498793bb74b5e5df7ca Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Sat, 9 Mar 2019 04:51:22 +0530 Subject: [PATCH 10/16] Skip the doc example in testing --- docs/sbpy/data.rst | 742 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 742 insertions(+) create mode 100644 docs/sbpy/data.rst diff --git a/docs/sbpy/data.rst b/docs/sbpy/data.rst new file mode 100644 index 000000000..eed843d88 --- /dev/null +++ b/docs/sbpy/data.rst @@ -0,0 +1,742 @@ +Data Module (`sbpy.data`) +========================= + +Introduction +------------ + +`sbpy.data` provides classes for dealing with orbital elements +(`~sbpy.data.Orbit`), ephemerides (`~sbpy.data.Ephem`), and physical +properties (`~sbpy.data.Phys`). `~sbpy.data.Ephem`, +`~sbpy.data.Orbit`, and `~sbpy.data.Phys` objects act as containers +for such parameters and can (and should) be used to provide these to +functions in `sbpy`. Each of these classes is based on the +`~sbpy.data.DataClass` base class, which internally uses an +`~astropy.table.QTable` object and provides the same functionality and +features as the latter. + +Furthermore, `~sbpy.data` also provides additional interfaces to a number of +different services and `~sbpy.data.Names` provides functions +related to naming conventions for asteroids and comets. + + +How to use Ephem, Orbit, and Phys objects +----------------------------------------- + +All of the data objects dealt with in `sbpy.data` share the same +common base class: `sbpy.data.DataClass`. `~sbpy.data.DataClass` +defines the basic functionality and makes sure that all `sbpy.data` +objects can used in the exact same way. + +In plain words, this means that in the following examples you can +replace `~sbpy.data.DataClass`, `~sbpy.data.Ephem`, +`~sbpy.data.Orbit`, and `~sbpy.data.Phys` object with each other. In +order to show some useful use cases, we will iterate between these +types, but keep in mind: they all work the exact same way. + +`~sbpy.data.DataClass` uses `~astropy.table.QTable` objects under the +hood. You can think of those as tables - consisting of columns and +rows - that have `~astropy.units` attached to them, allowing you to +propagate these units through your code. Each `~sbpy.data.DataClass` +object can hold as many data as you want, where each datum can be a +different object or the same object at a different epoch. + + +Building an object +^^^^^^^^^^^^^^^^^^ + +While `~sbpy.data.Ephem`, `~sbpy.data.Orbit`, and `~sbpy.data.Phys` +provide a range of convience functions to build objects containing +data, for instance from online data archives, it is easily possible to +build these objects from scratch. This can be done for input data +stored in dictionaries (`~sbpy.data.DataClass.from_dict`), lists or +arrays (`~sbpy.data.DataClass.from_array`), `~astropy.table.Table` +objects (`~sbpy.data.DataClass.from_table`), or from data files +(`~sbpy.data.DataClass.from_file`). + +Depending on how your input data are organized, you cean use different +options in different cases: + +1. Assume that you want to build an `~sbpy.data.Orbit` object to + propagate this orbit and obtain ephemerides. Since you are dealing + with a single orbit, the most convenient solution might be to use a + dictionary to build your object: + + >>> from sbpy.data import Orbit + >>> import astropy.units as u + >>> elements = {'a':1.234*u.au, 'e':0.1234, 'i':12.34*u.deg, + ... 'argper': 123.4*u.deg, 'node': 45.2*u.deg, + ... 'epoch': 2451200.5*u.d, 'true_anom':23.1*u.deg} + >>> orb = Orbit.from_dict(elements) + >>> print(orb) # doctest: +SKIP + + a e i argper node epoch true_anom + AU deg deg deg d deg + float64 float64 float64 float64 float64 float64 float64 + ------- ------- ------- ------- ------- --------- --------- + 1.234 0.1234 12.34 123.4 45.2 2451200.5 23.1 + + One quick note on building `~sbpy.data.DataClass` objects from + dictionaries: dictionaries have no intrinsic order. In dictionary + ``elements`` as defined here, there is no guarantee that ``'a'`` + will always be located before ``'e'`` when reading out the + dictionary item by item, which happens when the data table is built + in the background. Hence, the order of the resulting data table + columns has to be considered random. If you want to force a + specific order on the columns in your data table, you can use and + `~collections.OrderedDict` instead of a simple dictionary. The + order of elements in an `~collections.OrderedDict` will be the same + as the order of the data table columns. + +2. Now assume that you want to build an `~sbpy.data.Ephem` object + holding RA, Dec, and observation midtime for some target that you + observed. In this case, you could provide a list of three + dictionaries to `~sbpy.data.DataClass.from_dict`, which means a lot + of typing. Instead, you can use `~sbpy.data.DataClass.from_array`, + which allows to provide your input data in the form of a list, + tuple, or `~numpy.ndarray`: + + >>> from sbpy.data import Ephem + >>> import astropy.units as u + >>> from numpy import array + >>> ra = [10.223423, 10.233453, 10.243452]*u.deg + >>> dec = [-12.42123, -12.41562, -12.40435]*u.deg + >>> epoch = (2451523.5 + array([0.1234, 0.2345, 0.3525]))*u.d + >>> obs = Ephem.from_array([ra, dec, epoch], names=['ra', 'dec', 't']) + >>> print(obs) + + ra dec t + deg deg d + float64 float64 float64 + --------- --------- ------------ + 10.223423 -12.42123 2451523.6234 + 10.233453 -12.41562 2451523.7345 + 10.243452 -12.40435 2451523.8525 + +3. If your data are already available as a `~astropy.table.Table` or + `~astropy.table.QTable`, you can simply convert it into a + `~sbpy.data.DataClass` object using + `~sbpy.data.DataClass.from_table`. + +4. You can also read in the data from a file that should be properly + formatted (e.g., it should have a headline with the same number of + elements as there are columns) using + `~sbpy.data.DataClass.from_file`. This function merely serves as a + wrapper for `~astropy.table.Table.read` and uses the same + parameters as the latter function. You can read in an ASCII file + using the following lines: + + >>> from sbpy.data import Ephem + >>> data = Ephem.from_file('data.txt', format='ascii') # doctest: +SKIP + + Please note that `~sbpy.data.DataClass.from_file` is not able to + identify units automatically. If you want to take advantage for + `~astropy.units` you will have to assign these units manually later + on. + + +Accessing data +^^^^^^^^^^^^^^ + +In order to obtain a list of column names in a `~sbpy.data.DataClass` object, you can use `~sbpy.data.DataClass.column_names`: + + >>> obs.column_names + + +Each of these columns can be accessed easily, for instance: + + >>> print(obs['ra']) # doctest: +SKIP + [10.223423 10.233453 10.243452] deg + +which will return an `astropy.units.quantity.Quantity` object if that +column has an `astropy.unit` attached to it, or an +`astropy.table.column.Column` object if not. Both objects can be used +just like `numpy.ndarray` objects. + +Similarly, if you are interested in the first set of observations in +``obs``, you can use: + + >>> print(obs[0]) + ra dec t + deg deg d + --------- --------- ------------ + 10.223423 -12.42123 2451523.6234 + +which returns you a table with only the requested subset of the +data. In order to retrieve RA from the second observation, you can +combine both examples and do: + + >>> print(obs[1]['ra']) # doctest: +SKIP + 10.233453 deg + +Another - maybe more elegant - way to access data table columns is as +an attribute: + + >>> print(obs.ra) # doctest: +SKIP + [10.223423 10.233453 10.243452] deg + >>> print(obs.ra[1]) + 10.233453 deg + +Just like in any `~astropy.table.Table` or `~astropy.table.QTable` object, you can use slicing to obtain subset tables from your data, for instance: + + >>> print(obs['ra', 'dec']) # doctest: +SKIP + + ra dec + deg deg + --------- --------- + 10.223423 -12.42123 + 10.233453 -12.41562 + 10.243452 -12.40435 + + >>> print(obs[obs['ra'] <= 10.233453*u.deg]) # doctest: +SKIP + ra dec t + deg deg d + --------- --------- ------------ + 10.223423 -12.42123 2451523.6234 + 10.233453 -12.41562 2451523.7345 + +The results of these examples will be of the same data type as `obs` +(any type derived from `~sbpy.data.DataClass`, e.g., +`~sbpy.data.Ephem`, `~sbpy.data.Orbit`, ...) The latter example shown +here uses a condition to filter data (only those observations with RA +less than or equal to 10.233453 degrees; note that it is necessary +here to apply ``u.deg`` to the value that all the RAs are compared +against) but selects all the columns in the original table. + +If you ever need to access the actual `~astropy.table.QTable` object +that is inside each `~sbpy.data.DataClass` object, you can access it +as ``obs.table``, although this should usually not be necessary. + +Modifying an object +^^^^^^^^^^^^^^^^^^^ + +`~sbpy.data.DataClass` offers some convenience functions for object +modifications. It is trivial to add additional rows and columns to +these objects in the form of lists, arrays, or dictionaries. + +Let's assume you want to add some more observations to your ``obs`` +object: + + >>> obs.add_rows([[10.255460*u.deg, -12.39460*u.deg, 2451523.94653*u.d], + ... [10.265425*u.deg, -12.38246*u.deg, 2451524.0673*u.d]]) + 5 + >>> print(obs) + + ra dec t + deg deg d + float64 float64 float64 + --------- --------- ------------- + 10.223423 -12.42123 2451523.6234 + 10.233453 -12.41562 2451523.7345 + 10.243452 -12.40435 2451523.8525 + 10.25546 -12.3946 2451523.94653 + 10.265425 -12.38246 2451524.0673 + +or if you want to add a column to your object: + + >>> obs.add_column(['V', 'V', 'R', 'i', 'g'], name='filter') + 4 + >>> print(obs) + + ra dec t filter + deg deg d + float64 float64 float64 str1 + --------- --------- ------------- ------ + 10.223423 -12.42123 2451523.6234 V + 10.233453 -12.41562 2451523.7345 V + 10.243452 -12.40435 2451523.8525 R + 10.25546 -12.3946 2451523.94653 i + 10.265425 -12.38246 2451524.0673 g + +The same result can be achieved using the following syntax: + + >>> obs['filter2'] = ['V', 'V', 'R', 'i', 'g'] # doctest: +SKIP + >>> print(obs) # doctest: +SKIP + + ra dec t filter filter2 + deg deg d + float64 float64 float64 str1 str1 + --------- --------- ------------- ------ ------- + 10.223423 -12.42123 2451523.6234 V V + 10.233453 -12.41562 2451523.7345 V V + 10.243452 -12.40435 2451523.8525 R R + 10.25546 -12.3946 2451523.94653 i i + 10.265425 -12.38246 2451524.0673 g g + +Similarly, exisiting columns can be modified using: + + >>> obs['filter'] = ['g', 'i', 'R', 'V', 'V'] # doctest: +SKIP + +A few things to be mentioned here: + +* Note how both functions return the number of rows or columns in the + updated object. +* If you are adding rows, the elements in the rows will be assigned to + the column in the corresponding order of the table columns. The + `~astropy.units` of the row elements have to be of the same + dimension as the table columns (e.g., one of the table column units + is degrees, then the corresponding row element has to define an + angular distance: ``u.deg`` or ``u.rad``). +* Naturally, the number of columns and rows of the rows and columns + to be added has to be identical to the numbers in the data table. + +If you are trying to add a single row to your object data table, using +a dictionary might be the most convenient solution: + + >>> obs.add_rows({'ra':10.255460*u.deg, 'dec': -12.39460*u.deg, + ... 't': 2451524.14653*u.d, 'filter': 'z'}) + 6 + + +When adding a large number of rows to your object, it might be most +convenient to first convert all the new rows into new +`~sbpy.data.DataClass` object and then append that using +`~sbpy.data.DataClass.add_rows`: + + >>> obs2 = Ephem.from_array([[10.4545, 10.5656]*u.deg, + ... [-12.1212, -12.0434]*u.deg, + ... [2451524.14653, 2451524.23541]*u.d, + ... ['r', 'z']], + ... names=['ra', 'dec', 't', 'filter']) + >>> obs.add_rows(obs2) + 8 + +Individual elements, entire rows, and columns can be modified by +directly addressing them: + + >>> print(obs['ra']) # doctest: +SKIP + [10.223423 10.233453 10.243452 10.25546 10.265425 10.25546 10.4545 + 10.5656 ] deg + >>> obs['ra'][:] = obs['ra'] + 0.1*u.deg + >>> print(obs['ra']) # doctest: +SKIP + [10.323423 10.333453 10.343452 10.35546 10.365425 10.35546 10.5545 + 10.6656 ] deg + +Note the specific syntax in this case (``obs['ra'][:] = ...``) that +is required by `~astropy.table.Table` if you want to replace +an entire column. + +More complex data table modifications are possible by directly +accessing the underlying `~astropy.table.QTable` object. + +Writing object data to a file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +`~sbpy.data.DataClass` objects can be written to files using +`~sbpy.data.DataClass.to_file`: + + >>> obs.to_file('observations.dat') + +By default, the data are written in ASCII format, but other formats +are available, too (cf. `~astropy.table.Table.write`). + +Alternative field names +^^^^^^^^^^^^^^^^^^^^^^^ + +It is common practice to use a set of different names for the same +property. For instance, the orbital inclination can be referred to as +``'i'``, ``'inc'``, or ``'incl'`` - it's a matter of personal +taste. `~sbpy.data.DataClass` accounts for this fact and is able to +provide a number of alternative field or property names, as suggested +above. + +As an example, if your `~sbpy.data.Orbit` object has a column named +``'incl'`` but you try to get column ``'i'``, the object will +internally check if ``'i'`` is a legitimate alternative field name for +``'incl'``. The corresponding column is then returned. If you try to +get a field name that is not connected to any existing field name, a +``KeyError`` will be raised. + +The definition of alternative field names is done in the file +``sbpy/data/__init__.py``, using the list ``fieldnames``. This list is +automatically tested for potential naming conflicts, i.e., different +properties that share the same alternative field names, and a human-readable list is compiled upon building `sbpy`. + +The list of alternative field names is available here: :ref:`alternative_fieldnames`. + +Field conversions +^^^^^^^^^^^^^^^^^ + +There are parameters and properties that can be used synonymously, a +good example for which are an object's radius and diameter. `sbpy` +acknowledges identities like this by providing internal conversions +for such properties. Consider the following example: + + >>> from sbpy.data import Phys + >>> import astropy.units as u + >>> data = Phys.from_dict({'d': 10*u.km}) + >>> print('{:.1f}'.format(data['d'][0])) + 10.0 km + >>> print('{:.1f}'.format(data['radius'][0])) + 5.0 km + +Note that the radius is not explicitly defined in ``data``, but +derived internally upon querying it and added to the internal data table: + + >>> print(data.column_names) + + +How to use Ephem +---------------- + +As shown above (`How to use Ephem, Orbit, and Phys objects`_), +`~sbpy.data.Ephem` objects can be created on the fly. However, +`~sbpy.data.Ephem` can also be used to access ephemerides information +from remote services. For instance, the following few lines will query +ephemerides for asteroid Ceres on a given date and for the position of +Mauna Kea Observatory (IAU observatory code ``568``) from the `JPL Horizons service `_: + + >>> from sbpy.data import Ephem + >>> from astropy.time import Time + >>> epoch = Time('2018-08-03 14:20', scale='utc') # time in UT + >>> eph = Ephem.from_horizons('Ceres', + ... location='568', + ... epochs=epoch) + >>> print(eph) + + targetname datetime_str datetime_jd ... PABLat timescale + d ... deg + str7 str24 float64 ... float64 str3 + ---------- ------------------------ ----------------- ... ------- --------- + 1 Ceres 2018-Aug-03 14:20:00.000 2458334.097222222 ... 9.3473 UTC + + >>> print(eph.column_names) + + +`~sbpy.data.Ephem.from_horizons` uses one or more target names, an +observer location in the form of an IAU observatory code, and a list +of discrete epochs or a range of epochs defined in a dictionary (see +`~sbpy.data.Ephem.from_horizons`) to query the JPL Horizons +service. Due to different requirements of the JPL Horizons service for +the epoch format, we recommend to use `~astropy.time.Time` +objects. The column names in the data table can be inquired using +`~sbpy.data.DataClass.column_names`. + +`~sbpy.data.Ephem.from_horizons` is actually a wrapper around +`~astroquery.jplhorizons.HorizonsClass.ephemerides`. This function +conveniently combines the creation of a +`~astroquery.jplhorizons.HorizonsClass` query and the actual +ephemerides information retrieval into a single function. Additional +optional parameters provided to `~sbpy.data.Ephem.from_horizons` are +directly passed on to +`~astroquery.jplhorizons.HorizonsClass.ephemerides`, maintaining the +full flexibility of the latter function: + + >>> epoch1 = Time('2018-08-03 14:20', scale='utc') + >>> epoch2 = Time('2018-08-04 07:30', scale='utc') + >>> eph = Ephem.from_horizons('Ceres', + ... location='568', + ... epochs={'start': epoch1, + ... 'stop': epoch2, + ... 'step': '10m'}, + ... skip_daylight=True) + >>> print(eph) + + targetname datetime_str datetime_jd ... PABLon PABLat timescale + d ... deg deg + str7 str17 float64 ... float64 float64 str3 + ---------- ----------------- ----------------- ... -------- ------- --------- + 1 Ceres 2018-Aug-03 14:20 2458334.097222222 ... 171.275 9.3473 UTC + 1 Ceres 2018-Aug-03 14:30 2458334.104166667 ... 171.2774 9.3472 UTC + 1 Ceres 2018-Aug-03 14:40 2458334.111111111 ... 171.2798 9.3471 UTC + 1 Ceres 2018-Aug-03 14:50 2458334.118055556 ... 171.2822 9.347 UTC + 1 Ceres 2018-Aug-03 15:00 2458334.125 ... 171.2846 9.3469 UTC + 1 Ceres 2018-Aug-03 15:10 2458334.131944444 ... 171.2869 9.3468 UTC + ... ... ... ... ... ... ... + 1 Ceres 2018-Aug-04 06:40 2458334.777777778 ... 171.5076 9.3369 UTC + 1 Ceres 2018-Aug-04 06:50 2458334.784722222 ... 171.5099 9.3368 UTC + 1 Ceres 2018-Aug-04 07:00 2458334.791666667 ... 171.5123 9.3367 UTC + 1 Ceres 2018-Aug-04 07:10 2458334.798611111 ... 171.5147 9.3366 UTC + 1 Ceres 2018-Aug-04 07:20 2458334.805555556 ... 171.5171 9.3365 UTC + 1 Ceres 2018-Aug-04 07:30 2458334.8125 ... 171.5195 9.3364 UTC + +Note that ``skip_daylight`` is an optional parameter of +`~astroquery.jplhorizons.HorizonsClass.ephemerides` and it can be used +here as well. An additional feature of +`~sbpy.data.Ephem.from_horizons` is that you can automatically +concatenate queries for a number of objects: + + >>> eph = Ephem.from_horizons(['Ceres', 'Pallas', 12893, '1983 SA'], + ... location='568', + ... epochs=epoch1) + >>> print(eph) + + targetname datetime_str ... PABLat timescale + ... deg + str26 str24 ... float64 str3 + -------------------------- ------------------------ ... -------- --------- + 1 Ceres 2018-Aug-03 14:20:00.000 ... 9.3473 UTC + 2 Pallas 2018-Aug-03 14:20:00.000 ... -20.1396 UTC + 12893 Mommert (1998 QS55) 2018-Aug-03 14:20:00.000 ... -2.0567 UTC + 3552 Don Quixote (1983 SA) 2018-Aug-03 14:20:00.000 ... 13.3365 UTC + +Please be aware that these queries are not simultaneous. The more +targets you query, the longer the query will take. Furthermore, keep +in mind that asteroids and comets have slightly different table +layouts (e.g., different magnitude systems: ``T-mag`` and ``N-mag`` +instead of ``V-mag``), which will complicate the interpretation of the +data. It might be safest to query asteroids and comets separately. + +Similarly, the `~sbpy.data.Ephem.from_mpc` method will retrieve +ephemerides from the Minor Planet Center: + + >>> eph = Ephem.from_mpc('2P', location='568', + ... epochs={'start': '2018-10-22', + ... 'stop': '2018-10-26', + ... 'step': '1d'}) + >>> print(eph) + + Date timescale ... Moon distance Moon altitude + ... deg deg + object str3 ... float64 float64 + ----------------------- --------- ... ------------- ------------- + 2018-10-22 00:00:00.000 UTC ... 28.0 -33.0 + 2018-10-23 00:00:00.000 UTC ... 41.0 -41.0 + 2018-10-24 00:00:00.000 UTC ... 54.0 -48.0 + 2018-10-25 00:00:00.000 UTC ... 67.0 -53.0 + 2018-10-26 00:00:00.000 UTC ... 81.0 -56.0 + +Ephemerides can also be derived from `~Orbit` objects using `sbpy`'s +interface to `pyoorb +`_ with the function +`~sbpy.data.Ephem.from_oorb`. The following example computes +ephemerides for the next ten days in steps of 1 hr for Ceres as seen +from the Discovery Channel Telescope: + + >>> import numpy as np + >>> from sbpy.data import Orbit, Ephem + >>> from astropy.time import Time + >>> epochs = Time.now().jd + np.arange(0, 10, 1/24) + >>> ceres = Orbit.from_horizons('1') + >>> eph = Ephem.from_oo(ceres, epochs, 'G37') # doctest: +SKIP + >>> print(eph) # doctest: +SKIP + + targetname epoch ... obsz trueanom + d ... AU deg + str7 float64 ... float64 float64 + ---------- ------------------ ... ----------------------- ----------------- + 1 Ceres 2458519.2878717002 ... 4.886414464166933e-06 68.07980642088688 + 1 Ceres 2458519.3295383668 ... 2.3814767035612583e-06 68.0893160393968 + 1 Ceres 2458519.3712050337 ... -7.136200919632962e-07 68.09882544202566 + 1 Ceres 2458519.4128717002 ... -4.18340743346679e-06 68.10833462855386 + 1 Ceres 2458519.4545383668 ... -7.786747377891423e-06 68.11784359908062 + 1 Ceres 2458519.4962050337 ... -1.1273355301266719e-05 68.12735235370518 + ... ... ... ... ... + 1 Ceres 2458529.0378717002 ... 1.093565783852335e-05 70.29915515170745 + 1 Ceres 2458529.0795383668 ... 1.3089531693877277e-05 70.3086140523456 + 1 Ceres 2458529.1212050337 ... 1.4402894355114437e-05 70.31807273565124 + 1 Ceres 2458529.1628717002 ... 1.4786143903738891e-05 70.32753120140761 + 1 Ceres 2458529.2045383668 ... 1.4213398342149963e-05 70.33698944971509 + 1 Ceres 2458529.2462050337 ... 1.2724269065650384e-05 70.34644748067402 + +The properties computed by pyoorb and listed in the resulting table +are defined in the `pyoorb documentation +`_. Note that this function requires pyoorb to be installed, which is not a requirement for `sbpy`. + +How to use Orbit +---------------- + +`~sbpy.data.Orbit.from_horizons` enables the query of Solar System +body osculating elements from the `JPL Horizons service +`_: + + >>> from sbpy.data import Orbit + >>> from astropy.time import Time + >>> epoch = Time('2018-05-14', scale='utc') + >>> elem = Orbit.from_horizons('Ceres', epochs=epoch) + >>> print(elem) # doctest: +SKIP + + targetname datetime_jd ... P timescale + d ... d + str7 float64 ... float64 str2 + ---------- ----------- ... ----------------- --------- + 1 Ceres 2458252.5 ... 1681.218128428134 TT + >>> print(elem.column_names) + + +If ``epochs`` is not set, the osculating elements for the current +epoch (current time) are queried. Similar to +`~sbpy.data.Ephem.from_horizons`, this function is a wrapper for +`~astroquery.jplhorizons.HorizonsClass.elements` and passes optional +parameter on to that function. Furthermore, it is possible to query +orbital elements for a number of targets: + + >>> epoch = Time('2018-08-03 14:20', scale='utc') + >>> elem = Orbit.from_horizons(['3749', '2009 BR60'], + ... epochs=epoch, + ... refplane='earth') + >>> print(elem) # doctest: +SKIP + + targetname datetime_jd ... P timescale + d ... d + str21 float64 ... float64 str2 + --------------------- ----------------- ... ----------------- --------- + 3749 Balam (1982 BG1) 2458334.097222222 ... 1221.865723414031 TT + 312497 (2009 BR60) 2458334.097222222 ... 1221.776912893334 TT + +An existing `~Orbit` instance can be transformed to a different +orbital element definition system (e.g., Keplerian, cometary, +cartesian) using `~sbpy.data.Orbit.oo_transform` or it can be +propagated into the future or past using +`~sbpy.data.Orbit.oo_propagate`. Both functions are implemented in +`sbpy` to provide an interface to `pyoorb +`_, a Python module +using `OpenOrb `_. + +In order to transform some current orbits to a state vector in +cartesian coordinates, one could use the following code: + + >>> elem = Orbit.from_horizons(['Ceres', 'Pallas', 'Vesta']) + >>> statevec = elem.oo_transform('CART') # doctest: +SKIP + >>> print(statevec) # doctest: +SKIP + + id x y ... H G timescale + AU AU ... mag + str8 float64 float64 ... float64 float64 str2 + -------- ------------------- -------------------- ... ------- ------- --------- + 1 Ceres -1.9673670927605356 -1.788869179608663 ... 3.34 0.12 TT + 2 Pallas -2.354147777522819 -0.20413910825654025 ... 4.13 0.11 TT + 4 Vesta 2.142974769357926 -0.8590480100896669 ... 3.2 0.32 TT + +Orbits can currently be transformed to the following definitions: +cartesian (``'CART'``), Keplerian (``'KEP'``), and cometary +(``'COM'``). + +Orbit propagation requires the epoch to which the orbit should be +propagated to either as `~astropy.time.Time` object, or as float in +terms of Julian date. The following example propagates the current +orbit of Ceres back to year 2000: + + >>> elem = Orbit.from_horizons('Ceres') + >>> epoch = Time('2000-01-01', format='iso') + >>> newelem = elem.oo_propagate(epoch) # doctest: +SKIP + >>> print(newelem) # doctest: +SKIP + + id a e ... H G timescale + AU ... mag + str7 float64 float64 ... float64 float64 str3 + ------- ------------------ ------------------- ... ------- ------- --------- + 1 Ceres 2.7664942134894703 0.07837504303420217 ... 3.34 0.12 UTC + +Note that both functions require pyoorb to be installed, which is +not a requirement for `sbpy`. + +How to use Phys +--------------- + +`~sbpy.data.Phys` is designed to contain query physical properties for +small bodies; functions to query these properties are +available. `~sbpy.data.Phys.from_sbdb` queries the `JPL Small-body +Database Browser (SBDB) `_ for physical +properties and stores the data in a `~sbpy.data.Phys` object, offering +the same functionality as all the other `~sbpy.data` functions, +including the use of `~astropy.units`. + +As an example, the following code will query the properties for a +small number of asteroids: + + >>> from sbpy.data import Phys + >>> phys = Phys.from_sbdb(['Ceres', '12893', '3552']) + >>> print(phys['targetname', 'H', 'diameter']) # doctest: +SKIP + + targetname H diameter + km + str26 float64 float64 + -------------------------- ------- -------- + 1 Ceres 3.34 939.4 + 12893 Mommert (1998 QS55) 13.9 5.214 + 3552 Don Quixote (1983 SA) 12.9 19.0 + + +Please note that the SBDB database is not complete with respect to +physical properties and should be considered as a sparse dataset. + + + + +How to use Names +---------------- + +`~sbpy.data.Names` is different from the other classes in `~sbpy.data` +in that it does not use `~sbpy.data.DataClass` as a base class. Instead, +`~sbpy.data.Names` does not contain any data, it merely serves as an +umbrella for functions to identify asteroid and comet names, numbers, +and designations. + +In order to distinguish if a string designates a comet or an asteroid, +you can use the following code: + + >>> from sbpy.data import Names + >>> print(Names.asteroid_or_comet('(1) Ceres')) + asteroid + >>> print(Names.asteroid_or_comet('2P/Encke')) + comet + +The module basically uses regular expressions to match the input +strings and find patterns that agree with asteroid and comet names, +numbers, and designations. There are separate tasks to identify +asteroid and comet identifiers: + + >>> print(Names.parse_asteroid('(228195) 6675 P-L')) # doctest: +SKIP + {'number': 228195, 'desig': '6675 P-L'} + >>> print(Names.parse_asteroid('C/2001 A2-A (LINEAR)')) # doctest: +SKIP + ... sbpy.data.names.TargetNameParseError: C/2001 A2-A (LINEAR) does not appear to be an asteroid identifier + >>> print(Names.parse_comet('12893')) # doctest: +SKIP + ... sbpy.data.names.TargetNameParseError: 12893 does not appear to be a comet name + >>> print(Names.parse_comet('73P-C/Schwassmann Wachmann 3 C ')) # doctest: +SKIP + {'type': 'P', 'number': 73, 'fragment': 'C', 'name': 'Schwassmann Wachmann 3 C'} + +In order to be able to distinguish between asteroid and comet +identifiers, `sbpy` follows the MPC guideline in that it requires +comet identifiers to include the comet type in either in combination +with a number (e.g., ``'259P'``), a name (e.g., ``'P/Halley'``), or +both (e.g., ``'2P/Encke'``). For instance, the identifier ``'Halley'`` +would be identified as an asteroid, as it lacks a comet type +identifier. Hence, some caution is advised when using these routines - +identification might not be unambiguous. + +Sorting names with a natural sort order +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sorting with Python's built-in functions might not return the desired +order: + + >>> comets = ['9P/Tempel 1', + ... '101P/Chernykh', + ... '10P/Tempel 2', + ... '2P/Encke'] + >>> sorted(comets) + ['101P/Chernykh', '10P/Tempel 2', '2P/Encke', '9P/Tempel 1'] + +101P and 10P are placed at the start of the list because Python is +performing a string comparison, which is character-by-character, and +``'1' < '2'``. With `sbpy`'s ``natural_sort_key``, numerical +comparisons are made whenever possible: + + >>> from sbpy.data import natural_sort_key + >>> sorted(comets, key=natural_sort_key) + ['2P/Encke', '9P/Tempel 1', '10P/Tempel 2', '101P/Chernykh'] + +How to use the DASTCOM5 Module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For using the DASTCOM5 Module, you have to first download the databse locally. +That can be done by: + + >>> from sbpy.utils import dastcom5 + >>> dastcom5.download_dastcom5() # doctest: +SKIP + +After the database is downloaded, all the queries can be done easily. + +DASTCOM5 is a subset of Small Body Database provided by JPL, NASA. +For querying the database, either name or record number for the object +can be used. + + >>> dastcom5.orbit_from_name('atira') # doctest: +SKIP + >>> dastcom5.orbit_from_record(900001) # doctest: +SKIP + +More information about the DASTCOM5 Database can be taken from it's README file. + +Reference/API +------------- +.. automodapi:: sbpy.data + :no-heading: From 134336768e81e321c64b605114e8be1339719709 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Wed, 13 Mar 2019 16:47:13 +0530 Subject: [PATCH 11/16] Use Astropy table instead of pandas --- requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..f1032b728 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +numpy>=1.4.0 +astropy>=3.0<4.0 +matplotlib +ads +synphot<0.2 +git+git://github.com/astropy/astroquery.git@master#egg=astroquery From 605d9c7e306cdbe7d59d637fafa2b684cf01b13b Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Wed, 10 Apr 2019 04:08:23 +0530 Subject: [PATCH 12/16] Move dastcom to sbpy.data.utils --- sbpy/data/orbit.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sbpy/data/orbit.py b/sbpy/data/orbit.py index afdeb3635..0900f0fb6 100644 --- a/sbpy/data/orbit.py +++ b/sbpy/data/orbit.py @@ -19,7 +19,7 @@ from .. import bib from . import conf, DataClass -from .. import utils +from . import utils __all__ = ['Orbit', 'OrbitError', 'OpenOrbError'] @@ -181,14 +181,14 @@ def from_horizons(cls, targetids, id_type='smallbody', return cls.from_table(all_elem) @classmethod - def from_dastcom5(cls, name): + def from_dastcom5(cls, identifier, is_record_number=False): """Load orbital elements from the DASTCOM5 Database (ftp://ssd.jpl.nasa.gov/pub/ssd/dastcom5.zip). Parameters ---------- - name: str, mandatory - Name of NEO + identifier: mandatory + Names, numbers, or designations of objects to be queried Returns ------- @@ -205,7 +205,10 @@ def from_dastcom5(cls, name): if not os.path.isdir(dastcom5_dir): utils.dastcom5.download_dastcom5() - tb = utils.dastcom5.orbit_from_name(name=name) + if is_record_number: + tb = utils.dastcom5.orbit_from_record(record=identifier) + else: + tb = utils.dastcom5.orbit_from_name(name=identifier) return cls.from_table(tb) @classmethod From 878a87a995827eac1e16cc3bc7d2c243945c24c0 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Sat, 4 Jan 2020 17:25:20 +0530 Subject: [PATCH 13/16] Fix rebase artifacts --- docs/sbpy/data.rst | 742 --------------------------------------------- sbpy/data/orbit.py | 22 +- 2 files changed, 10 insertions(+), 754 deletions(-) delete mode 100644 docs/sbpy/data.rst diff --git a/docs/sbpy/data.rst b/docs/sbpy/data.rst deleted file mode 100644 index eed843d88..000000000 --- a/docs/sbpy/data.rst +++ /dev/null @@ -1,742 +0,0 @@ -Data Module (`sbpy.data`) -========================= - -Introduction ------------- - -`sbpy.data` provides classes for dealing with orbital elements -(`~sbpy.data.Orbit`), ephemerides (`~sbpy.data.Ephem`), and physical -properties (`~sbpy.data.Phys`). `~sbpy.data.Ephem`, -`~sbpy.data.Orbit`, and `~sbpy.data.Phys` objects act as containers -for such parameters and can (and should) be used to provide these to -functions in `sbpy`. Each of these classes is based on the -`~sbpy.data.DataClass` base class, which internally uses an -`~astropy.table.QTable` object and provides the same functionality and -features as the latter. - -Furthermore, `~sbpy.data` also provides additional interfaces to a number of -different services and `~sbpy.data.Names` provides functions -related to naming conventions for asteroids and comets. - - -How to use Ephem, Orbit, and Phys objects ------------------------------------------ - -All of the data objects dealt with in `sbpy.data` share the same -common base class: `sbpy.data.DataClass`. `~sbpy.data.DataClass` -defines the basic functionality and makes sure that all `sbpy.data` -objects can used in the exact same way. - -In plain words, this means that in the following examples you can -replace `~sbpy.data.DataClass`, `~sbpy.data.Ephem`, -`~sbpy.data.Orbit`, and `~sbpy.data.Phys` object with each other. In -order to show some useful use cases, we will iterate between these -types, but keep in mind: they all work the exact same way. - -`~sbpy.data.DataClass` uses `~astropy.table.QTable` objects under the -hood. You can think of those as tables - consisting of columns and -rows - that have `~astropy.units` attached to them, allowing you to -propagate these units through your code. Each `~sbpy.data.DataClass` -object can hold as many data as you want, where each datum can be a -different object or the same object at a different epoch. - - -Building an object -^^^^^^^^^^^^^^^^^^ - -While `~sbpy.data.Ephem`, `~sbpy.data.Orbit`, and `~sbpy.data.Phys` -provide a range of convience functions to build objects containing -data, for instance from online data archives, it is easily possible to -build these objects from scratch. This can be done for input data -stored in dictionaries (`~sbpy.data.DataClass.from_dict`), lists or -arrays (`~sbpy.data.DataClass.from_array`), `~astropy.table.Table` -objects (`~sbpy.data.DataClass.from_table`), or from data files -(`~sbpy.data.DataClass.from_file`). - -Depending on how your input data are organized, you cean use different -options in different cases: - -1. Assume that you want to build an `~sbpy.data.Orbit` object to - propagate this orbit and obtain ephemerides. Since you are dealing - with a single orbit, the most convenient solution might be to use a - dictionary to build your object: - - >>> from sbpy.data import Orbit - >>> import astropy.units as u - >>> elements = {'a':1.234*u.au, 'e':0.1234, 'i':12.34*u.deg, - ... 'argper': 123.4*u.deg, 'node': 45.2*u.deg, - ... 'epoch': 2451200.5*u.d, 'true_anom':23.1*u.deg} - >>> orb = Orbit.from_dict(elements) - >>> print(orb) # doctest: +SKIP - - a e i argper node epoch true_anom - AU deg deg deg d deg - float64 float64 float64 float64 float64 float64 float64 - ------- ------- ------- ------- ------- --------- --------- - 1.234 0.1234 12.34 123.4 45.2 2451200.5 23.1 - - One quick note on building `~sbpy.data.DataClass` objects from - dictionaries: dictionaries have no intrinsic order. In dictionary - ``elements`` as defined here, there is no guarantee that ``'a'`` - will always be located before ``'e'`` when reading out the - dictionary item by item, which happens when the data table is built - in the background. Hence, the order of the resulting data table - columns has to be considered random. If you want to force a - specific order on the columns in your data table, you can use and - `~collections.OrderedDict` instead of a simple dictionary. The - order of elements in an `~collections.OrderedDict` will be the same - as the order of the data table columns. - -2. Now assume that you want to build an `~sbpy.data.Ephem` object - holding RA, Dec, and observation midtime for some target that you - observed. In this case, you could provide a list of three - dictionaries to `~sbpy.data.DataClass.from_dict`, which means a lot - of typing. Instead, you can use `~sbpy.data.DataClass.from_array`, - which allows to provide your input data in the form of a list, - tuple, or `~numpy.ndarray`: - - >>> from sbpy.data import Ephem - >>> import astropy.units as u - >>> from numpy import array - >>> ra = [10.223423, 10.233453, 10.243452]*u.deg - >>> dec = [-12.42123, -12.41562, -12.40435]*u.deg - >>> epoch = (2451523.5 + array([0.1234, 0.2345, 0.3525]))*u.d - >>> obs = Ephem.from_array([ra, dec, epoch], names=['ra', 'dec', 't']) - >>> print(obs) - - ra dec t - deg deg d - float64 float64 float64 - --------- --------- ------------ - 10.223423 -12.42123 2451523.6234 - 10.233453 -12.41562 2451523.7345 - 10.243452 -12.40435 2451523.8525 - -3. If your data are already available as a `~astropy.table.Table` or - `~astropy.table.QTable`, you can simply convert it into a - `~sbpy.data.DataClass` object using - `~sbpy.data.DataClass.from_table`. - -4. You can also read in the data from a file that should be properly - formatted (e.g., it should have a headline with the same number of - elements as there are columns) using - `~sbpy.data.DataClass.from_file`. This function merely serves as a - wrapper for `~astropy.table.Table.read` and uses the same - parameters as the latter function. You can read in an ASCII file - using the following lines: - - >>> from sbpy.data import Ephem - >>> data = Ephem.from_file('data.txt', format='ascii') # doctest: +SKIP - - Please note that `~sbpy.data.DataClass.from_file` is not able to - identify units automatically. If you want to take advantage for - `~astropy.units` you will have to assign these units manually later - on. - - -Accessing data -^^^^^^^^^^^^^^ - -In order to obtain a list of column names in a `~sbpy.data.DataClass` object, you can use `~sbpy.data.DataClass.column_names`: - - >>> obs.column_names - - -Each of these columns can be accessed easily, for instance: - - >>> print(obs['ra']) # doctest: +SKIP - [10.223423 10.233453 10.243452] deg - -which will return an `astropy.units.quantity.Quantity` object if that -column has an `astropy.unit` attached to it, or an -`astropy.table.column.Column` object if not. Both objects can be used -just like `numpy.ndarray` objects. - -Similarly, if you are interested in the first set of observations in -``obs``, you can use: - - >>> print(obs[0]) - ra dec t - deg deg d - --------- --------- ------------ - 10.223423 -12.42123 2451523.6234 - -which returns you a table with only the requested subset of the -data. In order to retrieve RA from the second observation, you can -combine both examples and do: - - >>> print(obs[1]['ra']) # doctest: +SKIP - 10.233453 deg - -Another - maybe more elegant - way to access data table columns is as -an attribute: - - >>> print(obs.ra) # doctest: +SKIP - [10.223423 10.233453 10.243452] deg - >>> print(obs.ra[1]) - 10.233453 deg - -Just like in any `~astropy.table.Table` or `~astropy.table.QTable` object, you can use slicing to obtain subset tables from your data, for instance: - - >>> print(obs['ra', 'dec']) # doctest: +SKIP - - ra dec - deg deg - --------- --------- - 10.223423 -12.42123 - 10.233453 -12.41562 - 10.243452 -12.40435 - - >>> print(obs[obs['ra'] <= 10.233453*u.deg]) # doctest: +SKIP - ra dec t - deg deg d - --------- --------- ------------ - 10.223423 -12.42123 2451523.6234 - 10.233453 -12.41562 2451523.7345 - -The results of these examples will be of the same data type as `obs` -(any type derived from `~sbpy.data.DataClass`, e.g., -`~sbpy.data.Ephem`, `~sbpy.data.Orbit`, ...) The latter example shown -here uses a condition to filter data (only those observations with RA -less than or equal to 10.233453 degrees; note that it is necessary -here to apply ``u.deg`` to the value that all the RAs are compared -against) but selects all the columns in the original table. - -If you ever need to access the actual `~astropy.table.QTable` object -that is inside each `~sbpy.data.DataClass` object, you can access it -as ``obs.table``, although this should usually not be necessary. - -Modifying an object -^^^^^^^^^^^^^^^^^^^ - -`~sbpy.data.DataClass` offers some convenience functions for object -modifications. It is trivial to add additional rows and columns to -these objects in the form of lists, arrays, or dictionaries. - -Let's assume you want to add some more observations to your ``obs`` -object: - - >>> obs.add_rows([[10.255460*u.deg, -12.39460*u.deg, 2451523.94653*u.d], - ... [10.265425*u.deg, -12.38246*u.deg, 2451524.0673*u.d]]) - 5 - >>> print(obs) - - ra dec t - deg deg d - float64 float64 float64 - --------- --------- ------------- - 10.223423 -12.42123 2451523.6234 - 10.233453 -12.41562 2451523.7345 - 10.243452 -12.40435 2451523.8525 - 10.25546 -12.3946 2451523.94653 - 10.265425 -12.38246 2451524.0673 - -or if you want to add a column to your object: - - >>> obs.add_column(['V', 'V', 'R', 'i', 'g'], name='filter') - 4 - >>> print(obs) - - ra dec t filter - deg deg d - float64 float64 float64 str1 - --------- --------- ------------- ------ - 10.223423 -12.42123 2451523.6234 V - 10.233453 -12.41562 2451523.7345 V - 10.243452 -12.40435 2451523.8525 R - 10.25546 -12.3946 2451523.94653 i - 10.265425 -12.38246 2451524.0673 g - -The same result can be achieved using the following syntax: - - >>> obs['filter2'] = ['V', 'V', 'R', 'i', 'g'] # doctest: +SKIP - >>> print(obs) # doctest: +SKIP - - ra dec t filter filter2 - deg deg d - float64 float64 float64 str1 str1 - --------- --------- ------------- ------ ------- - 10.223423 -12.42123 2451523.6234 V V - 10.233453 -12.41562 2451523.7345 V V - 10.243452 -12.40435 2451523.8525 R R - 10.25546 -12.3946 2451523.94653 i i - 10.265425 -12.38246 2451524.0673 g g - -Similarly, exisiting columns can be modified using: - - >>> obs['filter'] = ['g', 'i', 'R', 'V', 'V'] # doctest: +SKIP - -A few things to be mentioned here: - -* Note how both functions return the number of rows or columns in the - updated object. -* If you are adding rows, the elements in the rows will be assigned to - the column in the corresponding order of the table columns. The - `~astropy.units` of the row elements have to be of the same - dimension as the table columns (e.g., one of the table column units - is degrees, then the corresponding row element has to define an - angular distance: ``u.deg`` or ``u.rad``). -* Naturally, the number of columns and rows of the rows and columns - to be added has to be identical to the numbers in the data table. - -If you are trying to add a single row to your object data table, using -a dictionary might be the most convenient solution: - - >>> obs.add_rows({'ra':10.255460*u.deg, 'dec': -12.39460*u.deg, - ... 't': 2451524.14653*u.d, 'filter': 'z'}) - 6 - - -When adding a large number of rows to your object, it might be most -convenient to first convert all the new rows into new -`~sbpy.data.DataClass` object and then append that using -`~sbpy.data.DataClass.add_rows`: - - >>> obs2 = Ephem.from_array([[10.4545, 10.5656]*u.deg, - ... [-12.1212, -12.0434]*u.deg, - ... [2451524.14653, 2451524.23541]*u.d, - ... ['r', 'z']], - ... names=['ra', 'dec', 't', 'filter']) - >>> obs.add_rows(obs2) - 8 - -Individual elements, entire rows, and columns can be modified by -directly addressing them: - - >>> print(obs['ra']) # doctest: +SKIP - [10.223423 10.233453 10.243452 10.25546 10.265425 10.25546 10.4545 - 10.5656 ] deg - >>> obs['ra'][:] = obs['ra'] + 0.1*u.deg - >>> print(obs['ra']) # doctest: +SKIP - [10.323423 10.333453 10.343452 10.35546 10.365425 10.35546 10.5545 - 10.6656 ] deg - -Note the specific syntax in this case (``obs['ra'][:] = ...``) that -is required by `~astropy.table.Table` if you want to replace -an entire column. - -More complex data table modifications are possible by directly -accessing the underlying `~astropy.table.QTable` object. - -Writing object data to a file -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -`~sbpy.data.DataClass` objects can be written to files using -`~sbpy.data.DataClass.to_file`: - - >>> obs.to_file('observations.dat') - -By default, the data are written in ASCII format, but other formats -are available, too (cf. `~astropy.table.Table.write`). - -Alternative field names -^^^^^^^^^^^^^^^^^^^^^^^ - -It is common practice to use a set of different names for the same -property. For instance, the orbital inclination can be referred to as -``'i'``, ``'inc'``, or ``'incl'`` - it's a matter of personal -taste. `~sbpy.data.DataClass` accounts for this fact and is able to -provide a number of alternative field or property names, as suggested -above. - -As an example, if your `~sbpy.data.Orbit` object has a column named -``'incl'`` but you try to get column ``'i'``, the object will -internally check if ``'i'`` is a legitimate alternative field name for -``'incl'``. The corresponding column is then returned. If you try to -get a field name that is not connected to any existing field name, a -``KeyError`` will be raised. - -The definition of alternative field names is done in the file -``sbpy/data/__init__.py``, using the list ``fieldnames``. This list is -automatically tested for potential naming conflicts, i.e., different -properties that share the same alternative field names, and a human-readable list is compiled upon building `sbpy`. - -The list of alternative field names is available here: :ref:`alternative_fieldnames`. - -Field conversions -^^^^^^^^^^^^^^^^^ - -There are parameters and properties that can be used synonymously, a -good example for which are an object's radius and diameter. `sbpy` -acknowledges identities like this by providing internal conversions -for such properties. Consider the following example: - - >>> from sbpy.data import Phys - >>> import astropy.units as u - >>> data = Phys.from_dict({'d': 10*u.km}) - >>> print('{:.1f}'.format(data['d'][0])) - 10.0 km - >>> print('{:.1f}'.format(data['radius'][0])) - 5.0 km - -Note that the radius is not explicitly defined in ``data``, but -derived internally upon querying it and added to the internal data table: - - >>> print(data.column_names) - - -How to use Ephem ----------------- - -As shown above (`How to use Ephem, Orbit, and Phys objects`_), -`~sbpy.data.Ephem` objects can be created on the fly. However, -`~sbpy.data.Ephem` can also be used to access ephemerides information -from remote services. For instance, the following few lines will query -ephemerides for asteroid Ceres on a given date and for the position of -Mauna Kea Observatory (IAU observatory code ``568``) from the `JPL Horizons service `_: - - >>> from sbpy.data import Ephem - >>> from astropy.time import Time - >>> epoch = Time('2018-08-03 14:20', scale='utc') # time in UT - >>> eph = Ephem.from_horizons('Ceres', - ... location='568', - ... epochs=epoch) - >>> print(eph) - - targetname datetime_str datetime_jd ... PABLat timescale - d ... deg - str7 str24 float64 ... float64 str3 - ---------- ------------------------ ----------------- ... ------- --------- - 1 Ceres 2018-Aug-03 14:20:00.000 2458334.097222222 ... 9.3473 UTC - - >>> print(eph.column_names) - - -`~sbpy.data.Ephem.from_horizons` uses one or more target names, an -observer location in the form of an IAU observatory code, and a list -of discrete epochs or a range of epochs defined in a dictionary (see -`~sbpy.data.Ephem.from_horizons`) to query the JPL Horizons -service. Due to different requirements of the JPL Horizons service for -the epoch format, we recommend to use `~astropy.time.Time` -objects. The column names in the data table can be inquired using -`~sbpy.data.DataClass.column_names`. - -`~sbpy.data.Ephem.from_horizons` is actually a wrapper around -`~astroquery.jplhorizons.HorizonsClass.ephemerides`. This function -conveniently combines the creation of a -`~astroquery.jplhorizons.HorizonsClass` query and the actual -ephemerides information retrieval into a single function. Additional -optional parameters provided to `~sbpy.data.Ephem.from_horizons` are -directly passed on to -`~astroquery.jplhorizons.HorizonsClass.ephemerides`, maintaining the -full flexibility of the latter function: - - >>> epoch1 = Time('2018-08-03 14:20', scale='utc') - >>> epoch2 = Time('2018-08-04 07:30', scale='utc') - >>> eph = Ephem.from_horizons('Ceres', - ... location='568', - ... epochs={'start': epoch1, - ... 'stop': epoch2, - ... 'step': '10m'}, - ... skip_daylight=True) - >>> print(eph) - - targetname datetime_str datetime_jd ... PABLon PABLat timescale - d ... deg deg - str7 str17 float64 ... float64 float64 str3 - ---------- ----------------- ----------------- ... -------- ------- --------- - 1 Ceres 2018-Aug-03 14:20 2458334.097222222 ... 171.275 9.3473 UTC - 1 Ceres 2018-Aug-03 14:30 2458334.104166667 ... 171.2774 9.3472 UTC - 1 Ceres 2018-Aug-03 14:40 2458334.111111111 ... 171.2798 9.3471 UTC - 1 Ceres 2018-Aug-03 14:50 2458334.118055556 ... 171.2822 9.347 UTC - 1 Ceres 2018-Aug-03 15:00 2458334.125 ... 171.2846 9.3469 UTC - 1 Ceres 2018-Aug-03 15:10 2458334.131944444 ... 171.2869 9.3468 UTC - ... ... ... ... ... ... ... - 1 Ceres 2018-Aug-04 06:40 2458334.777777778 ... 171.5076 9.3369 UTC - 1 Ceres 2018-Aug-04 06:50 2458334.784722222 ... 171.5099 9.3368 UTC - 1 Ceres 2018-Aug-04 07:00 2458334.791666667 ... 171.5123 9.3367 UTC - 1 Ceres 2018-Aug-04 07:10 2458334.798611111 ... 171.5147 9.3366 UTC - 1 Ceres 2018-Aug-04 07:20 2458334.805555556 ... 171.5171 9.3365 UTC - 1 Ceres 2018-Aug-04 07:30 2458334.8125 ... 171.5195 9.3364 UTC - -Note that ``skip_daylight`` is an optional parameter of -`~astroquery.jplhorizons.HorizonsClass.ephemerides` and it can be used -here as well. An additional feature of -`~sbpy.data.Ephem.from_horizons` is that you can automatically -concatenate queries for a number of objects: - - >>> eph = Ephem.from_horizons(['Ceres', 'Pallas', 12893, '1983 SA'], - ... location='568', - ... epochs=epoch1) - >>> print(eph) - - targetname datetime_str ... PABLat timescale - ... deg - str26 str24 ... float64 str3 - -------------------------- ------------------------ ... -------- --------- - 1 Ceres 2018-Aug-03 14:20:00.000 ... 9.3473 UTC - 2 Pallas 2018-Aug-03 14:20:00.000 ... -20.1396 UTC - 12893 Mommert (1998 QS55) 2018-Aug-03 14:20:00.000 ... -2.0567 UTC - 3552 Don Quixote (1983 SA) 2018-Aug-03 14:20:00.000 ... 13.3365 UTC - -Please be aware that these queries are not simultaneous. The more -targets you query, the longer the query will take. Furthermore, keep -in mind that asteroids and comets have slightly different table -layouts (e.g., different magnitude systems: ``T-mag`` and ``N-mag`` -instead of ``V-mag``), which will complicate the interpretation of the -data. It might be safest to query asteroids and comets separately. - -Similarly, the `~sbpy.data.Ephem.from_mpc` method will retrieve -ephemerides from the Minor Planet Center: - - >>> eph = Ephem.from_mpc('2P', location='568', - ... epochs={'start': '2018-10-22', - ... 'stop': '2018-10-26', - ... 'step': '1d'}) - >>> print(eph) - - Date timescale ... Moon distance Moon altitude - ... deg deg - object str3 ... float64 float64 - ----------------------- --------- ... ------------- ------------- - 2018-10-22 00:00:00.000 UTC ... 28.0 -33.0 - 2018-10-23 00:00:00.000 UTC ... 41.0 -41.0 - 2018-10-24 00:00:00.000 UTC ... 54.0 -48.0 - 2018-10-25 00:00:00.000 UTC ... 67.0 -53.0 - 2018-10-26 00:00:00.000 UTC ... 81.0 -56.0 - -Ephemerides can also be derived from `~Orbit` objects using `sbpy`'s -interface to `pyoorb -`_ with the function -`~sbpy.data.Ephem.from_oorb`. The following example computes -ephemerides for the next ten days in steps of 1 hr for Ceres as seen -from the Discovery Channel Telescope: - - >>> import numpy as np - >>> from sbpy.data import Orbit, Ephem - >>> from astropy.time import Time - >>> epochs = Time.now().jd + np.arange(0, 10, 1/24) - >>> ceres = Orbit.from_horizons('1') - >>> eph = Ephem.from_oo(ceres, epochs, 'G37') # doctest: +SKIP - >>> print(eph) # doctest: +SKIP - - targetname epoch ... obsz trueanom - d ... AU deg - str7 float64 ... float64 float64 - ---------- ------------------ ... ----------------------- ----------------- - 1 Ceres 2458519.2878717002 ... 4.886414464166933e-06 68.07980642088688 - 1 Ceres 2458519.3295383668 ... 2.3814767035612583e-06 68.0893160393968 - 1 Ceres 2458519.3712050337 ... -7.136200919632962e-07 68.09882544202566 - 1 Ceres 2458519.4128717002 ... -4.18340743346679e-06 68.10833462855386 - 1 Ceres 2458519.4545383668 ... -7.786747377891423e-06 68.11784359908062 - 1 Ceres 2458519.4962050337 ... -1.1273355301266719e-05 68.12735235370518 - ... ... ... ... ... - 1 Ceres 2458529.0378717002 ... 1.093565783852335e-05 70.29915515170745 - 1 Ceres 2458529.0795383668 ... 1.3089531693877277e-05 70.3086140523456 - 1 Ceres 2458529.1212050337 ... 1.4402894355114437e-05 70.31807273565124 - 1 Ceres 2458529.1628717002 ... 1.4786143903738891e-05 70.32753120140761 - 1 Ceres 2458529.2045383668 ... 1.4213398342149963e-05 70.33698944971509 - 1 Ceres 2458529.2462050337 ... 1.2724269065650384e-05 70.34644748067402 - -The properties computed by pyoorb and listed in the resulting table -are defined in the `pyoorb documentation -`_. Note that this function requires pyoorb to be installed, which is not a requirement for `sbpy`. - -How to use Orbit ----------------- - -`~sbpy.data.Orbit.from_horizons` enables the query of Solar System -body osculating elements from the `JPL Horizons service -`_: - - >>> from sbpy.data import Orbit - >>> from astropy.time import Time - >>> epoch = Time('2018-05-14', scale='utc') - >>> elem = Orbit.from_horizons('Ceres', epochs=epoch) - >>> print(elem) # doctest: +SKIP - - targetname datetime_jd ... P timescale - d ... d - str7 float64 ... float64 str2 - ---------- ----------- ... ----------------- --------- - 1 Ceres 2458252.5 ... 1681.218128428134 TT - >>> print(elem.column_names) - - -If ``epochs`` is not set, the osculating elements for the current -epoch (current time) are queried. Similar to -`~sbpy.data.Ephem.from_horizons`, this function is a wrapper for -`~astroquery.jplhorizons.HorizonsClass.elements` and passes optional -parameter on to that function. Furthermore, it is possible to query -orbital elements for a number of targets: - - >>> epoch = Time('2018-08-03 14:20', scale='utc') - >>> elem = Orbit.from_horizons(['3749', '2009 BR60'], - ... epochs=epoch, - ... refplane='earth') - >>> print(elem) # doctest: +SKIP - - targetname datetime_jd ... P timescale - d ... d - str21 float64 ... float64 str2 - --------------------- ----------------- ... ----------------- --------- - 3749 Balam (1982 BG1) 2458334.097222222 ... 1221.865723414031 TT - 312497 (2009 BR60) 2458334.097222222 ... 1221.776912893334 TT - -An existing `~Orbit` instance can be transformed to a different -orbital element definition system (e.g., Keplerian, cometary, -cartesian) using `~sbpy.data.Orbit.oo_transform` or it can be -propagated into the future or past using -`~sbpy.data.Orbit.oo_propagate`. Both functions are implemented in -`sbpy` to provide an interface to `pyoorb -`_, a Python module -using `OpenOrb `_. - -In order to transform some current orbits to a state vector in -cartesian coordinates, one could use the following code: - - >>> elem = Orbit.from_horizons(['Ceres', 'Pallas', 'Vesta']) - >>> statevec = elem.oo_transform('CART') # doctest: +SKIP - >>> print(statevec) # doctest: +SKIP - - id x y ... H G timescale - AU AU ... mag - str8 float64 float64 ... float64 float64 str2 - -------- ------------------- -------------------- ... ------- ------- --------- - 1 Ceres -1.9673670927605356 -1.788869179608663 ... 3.34 0.12 TT - 2 Pallas -2.354147777522819 -0.20413910825654025 ... 4.13 0.11 TT - 4 Vesta 2.142974769357926 -0.8590480100896669 ... 3.2 0.32 TT - -Orbits can currently be transformed to the following definitions: -cartesian (``'CART'``), Keplerian (``'KEP'``), and cometary -(``'COM'``). - -Orbit propagation requires the epoch to which the orbit should be -propagated to either as `~astropy.time.Time` object, or as float in -terms of Julian date. The following example propagates the current -orbit of Ceres back to year 2000: - - >>> elem = Orbit.from_horizons('Ceres') - >>> epoch = Time('2000-01-01', format='iso') - >>> newelem = elem.oo_propagate(epoch) # doctest: +SKIP - >>> print(newelem) # doctest: +SKIP - - id a e ... H G timescale - AU ... mag - str7 float64 float64 ... float64 float64 str3 - ------- ------------------ ------------------- ... ------- ------- --------- - 1 Ceres 2.7664942134894703 0.07837504303420217 ... 3.34 0.12 UTC - -Note that both functions require pyoorb to be installed, which is -not a requirement for `sbpy`. - -How to use Phys ---------------- - -`~sbpy.data.Phys` is designed to contain query physical properties for -small bodies; functions to query these properties are -available. `~sbpy.data.Phys.from_sbdb` queries the `JPL Small-body -Database Browser (SBDB) `_ for physical -properties and stores the data in a `~sbpy.data.Phys` object, offering -the same functionality as all the other `~sbpy.data` functions, -including the use of `~astropy.units`. - -As an example, the following code will query the properties for a -small number of asteroids: - - >>> from sbpy.data import Phys - >>> phys = Phys.from_sbdb(['Ceres', '12893', '3552']) - >>> print(phys['targetname', 'H', 'diameter']) # doctest: +SKIP - - targetname H diameter - km - str26 float64 float64 - -------------------------- ------- -------- - 1 Ceres 3.34 939.4 - 12893 Mommert (1998 QS55) 13.9 5.214 - 3552 Don Quixote (1983 SA) 12.9 19.0 - - -Please note that the SBDB database is not complete with respect to -physical properties and should be considered as a sparse dataset. - - - - -How to use Names ----------------- - -`~sbpy.data.Names` is different from the other classes in `~sbpy.data` -in that it does not use `~sbpy.data.DataClass` as a base class. Instead, -`~sbpy.data.Names` does not contain any data, it merely serves as an -umbrella for functions to identify asteroid and comet names, numbers, -and designations. - -In order to distinguish if a string designates a comet or an asteroid, -you can use the following code: - - >>> from sbpy.data import Names - >>> print(Names.asteroid_or_comet('(1) Ceres')) - asteroid - >>> print(Names.asteroid_or_comet('2P/Encke')) - comet - -The module basically uses regular expressions to match the input -strings and find patterns that agree with asteroid and comet names, -numbers, and designations. There are separate tasks to identify -asteroid and comet identifiers: - - >>> print(Names.parse_asteroid('(228195) 6675 P-L')) # doctest: +SKIP - {'number': 228195, 'desig': '6675 P-L'} - >>> print(Names.parse_asteroid('C/2001 A2-A (LINEAR)')) # doctest: +SKIP - ... sbpy.data.names.TargetNameParseError: C/2001 A2-A (LINEAR) does not appear to be an asteroid identifier - >>> print(Names.parse_comet('12893')) # doctest: +SKIP - ... sbpy.data.names.TargetNameParseError: 12893 does not appear to be a comet name - >>> print(Names.parse_comet('73P-C/Schwassmann Wachmann 3 C ')) # doctest: +SKIP - {'type': 'P', 'number': 73, 'fragment': 'C', 'name': 'Schwassmann Wachmann 3 C'} - -In order to be able to distinguish between asteroid and comet -identifiers, `sbpy` follows the MPC guideline in that it requires -comet identifiers to include the comet type in either in combination -with a number (e.g., ``'259P'``), a name (e.g., ``'P/Halley'``), or -both (e.g., ``'2P/Encke'``). For instance, the identifier ``'Halley'`` -would be identified as an asteroid, as it lacks a comet type -identifier. Hence, some caution is advised when using these routines - -identification might not be unambiguous. - -Sorting names with a natural sort order -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Sorting with Python's built-in functions might not return the desired -order: - - >>> comets = ['9P/Tempel 1', - ... '101P/Chernykh', - ... '10P/Tempel 2', - ... '2P/Encke'] - >>> sorted(comets) - ['101P/Chernykh', '10P/Tempel 2', '2P/Encke', '9P/Tempel 1'] - -101P and 10P are placed at the start of the list because Python is -performing a string comparison, which is character-by-character, and -``'1' < '2'``. With `sbpy`'s ``natural_sort_key``, numerical -comparisons are made whenever possible: - - >>> from sbpy.data import natural_sort_key - >>> sorted(comets, key=natural_sort_key) - ['2P/Encke', '9P/Tempel 1', '10P/Tempel 2', '101P/Chernykh'] - -How to use the DASTCOM5 Module -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For using the DASTCOM5 Module, you have to first download the databse locally. -That can be done by: - - >>> from sbpy.utils import dastcom5 - >>> dastcom5.download_dastcom5() # doctest: +SKIP - -After the database is downloaded, all the queries can be done easily. - -DASTCOM5 is a subset of Small Body Database provided by JPL, NASA. -For querying the database, either name or record number for the object -can be used. - - >>> dastcom5.orbit_from_name('atira') # doctest: +SKIP - >>> dastcom5.orbit_from_record(900001) # doctest: +SKIP - -More information about the DASTCOM5 Database can be taken from it's README file. - -Reference/API -------------- -.. automodapi:: sbpy.data - :no-heading: diff --git a/sbpy/data/orbit.py b/sbpy/data/orbit.py index 0900f0fb6..6820e2146 100644 --- a/sbpy/data/orbit.py +++ b/sbpy/data/orbit.py @@ -17,9 +17,11 @@ import astropy.units as u from warnings import warn -from .. import bib -from . import conf, DataClass -from . import utils +from ..bib import cite +from ..exceptions import SbpyException +from . import conf, utils, DataClass, QueryError, TimeScaleWarning + + __all__ = ['Orbit', 'OrbitError', 'OpenOrbError'] @@ -181,14 +183,14 @@ def from_horizons(cls, targetids, id_type='smallbody', return cls.from_table(all_elem) @classmethod - def from_dastcom5(cls, identifier, is_record_number=False): + def from_dastcom5(cls, name): """Load orbital elements from the DASTCOM5 Database (ftp://ssd.jpl.nasa.gov/pub/ssd/dastcom5.zip). Parameters ---------- - identifier: mandatory - Names, numbers, or designations of objects to be queried + name: str, mandatory + Name of NEO Returns ------- @@ -205,15 +207,11 @@ def from_dastcom5(cls, identifier, is_record_number=False): if not os.path.isdir(dastcom5_dir): utils.dastcom5.download_dastcom5() - if is_record_number: - tb = utils.dastcom5.orbit_from_record(record=identifier) - else: - tb = utils.dastcom5.orbit_from_name(name=identifier) + tb = utils.dastcom5.orbit_from_name(name=name) return cls.from_table(tb) @classmethod - @cite({'data source': - 'https://minorplanetcenter.net/iau/MPEph/MPEph.html'}) + @cite({'data source': 'https://minorplanetcenter.net/iau/MPEph/MPEph.html'}) @cite({'software: astroquery': '2019AJ....157...98G'}) def from_mpc(cls, targetids, id_type=None, target_type=None, **kwargs): """Load latest orbital elements from the From 99fe232427a58d12ca828e61febfd91092bc098b Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Sat, 4 Jan 2020 18:36:22 +0530 Subject: [PATCH 14/16] Add a parser function --- sbpy/data/utils/dastcom5.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/sbpy/data/utils/dastcom5.py b/sbpy/data/utils/dastcom5.py index fa297a332..83e05b91c 100644 --- a/sbpy/data/utils/dastcom5.py +++ b/sbpy/data/utils/dastcom5.py @@ -7,7 +7,7 @@ import astropy.units as u import numpy as np from astropy.time import Time -from astropy.table import Table, vstack +from astropy.table import Table, vstack, QTable import astropy.units as u AST_DTYPE = np.dtype( @@ -335,6 +335,34 @@ def orbit_from_name(name): return tbl +def orbit_parser(name): + """Return :py:class:`~astropy.table.QTable` given a name. + + Retrieve info with proper units from JPL DASTCOM5 database. + + Parameters + ---------- + name : str + NEO name. + + Returns + ------- + QTable : ~astropy.table.QTable + Near Earth Asteroid/Comet orbit parameters, all stacked. + + """ + orb = orbit_from_name(name) + record = [int(orb[1][0][0]),] + a = [float(orb[1][0][1]),] * u.au + ecc = [float(orb[1][0][2]),] * u.one + inc = [float(orb[1][0][3]),] * u.deg + raan = [float(orb[1][0][4]),] * u.deg + argp = [float(orb[1][0][5]),] * u.deg + m = [float(orb[1][0][6]),] * u.deg + epoch = [orb[1][0][7],] + tab = QTable([record, a, ecc, inc, raan, argp, m, epoch], names=("record", "a", "ecc", "inc", "raan", "argp", "m", "EPOCH")) + return tab + def orbit_from_record(record): """Return :py:class:`~astropy.table.Table` given a record. @@ -359,8 +387,8 @@ def orbit_from_record(record): argp = body_data["W"].item() m = body_data["MA"].item() epoch = Time(body_data["EPOCH"].item(), format="jd", scale="tdb") - column2 = (record, a, ecc, inc, raan, argp, m, epoch) - column1 = ("record", "a", "ecc", "inc", "raan", "argp", "m", "EPOCH") + column2 = [record, a, ecc, inc, raan, argp, m, epoch] + column1 = ["record", "a", "ecc", "inc", "raan", "argp", "m", "EPOCH"] data = Table(rows=[column1, column2]) return data From f0f2b98352a6b194a3a393146318a950c78a2411 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Tue, 31 Mar 2020 11:02:22 +0530 Subject: [PATCH 15/16] Fix some more rebase artifacts --- sbpy/data/orbit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbpy/data/orbit.py b/sbpy/data/orbit.py index 6820e2146..80091c32c 100644 --- a/sbpy/data/orbit.py +++ b/sbpy/data/orbit.py @@ -211,7 +211,8 @@ def from_dastcom5(cls, name): return cls.from_table(tb) @classmethod - @cite({'data source': 'https://minorplanetcenter.net/iau/MPEph/MPEph.html'}) + @cite({'data source': + 'https://minorplanetcenter.net/iau/MPEph/MPEph.html'}) @cite({'software: astroquery': '2019AJ....157...98G'}) def from_mpc(cls, targetids, id_type=None, target_type=None, **kwargs): """Load latest orbital elements from the From 2d0bf04c93f039fcef317734567b19bfa82f6593 Mon Sep 17 00:00:00 2001 From: Shreyas Bapat Date: Tue, 31 Mar 2020 11:23:22 +0530 Subject: [PATCH 16/16] MArk remote tests --- astropy_helpers | 2 +- docs/sbpy/data/dastcom5.rst | 2 +- requirements.txt | 6 ------ sbpy/data/utils/tests/test_dastcom5.py | 3 +++ 4 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 requirements.txt diff --git a/astropy_helpers b/astropy_helpers index d2a6304a3..231c409a6 160000 --- a/astropy_helpers +++ b/astropy_helpers @@ -1 +1 @@ -Subproject commit d2a6304a3e801bc2cb053ccf1cf09a9f1e62036c +Subproject commit 231c409a632dcbf2beae1c2dea5b843d81ede511 diff --git a/docs/sbpy/data/dastcom5.rst b/docs/sbpy/data/dastcom5.rst index 8ac4ace15..c06d3cd27 100644 --- a/docs/sbpy/data/dastcom5.rst +++ b/docs/sbpy/data/dastcom5.rst @@ -6,7 +6,7 @@ Using DASTCOM5 For using the DASTCOM5 Module, you have to first download the databse locally. That can be done by: - >>> from sbpy.utils import dastcom5 + >>> from sbpy.data.utils import dastcom5 >>> dastcom5.download_dastcom5() # doctest: +SKIP After the database is downloaded, all the queries can be done easily. diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f1032b728..000000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -numpy>=1.4.0 -astropy>=3.0<4.0 -matplotlib -ads -synphot<0.2 -git+git://github.com/astropy/astroquery.git@master#egg=astroquery diff --git a/sbpy/data/utils/tests/test_dastcom5.py b/sbpy/data/utils/tests/test_dastcom5.py index 1e6b8f3c1..ccba38abe 100644 --- a/sbpy/data/utils/tests/test_dastcom5.py +++ b/sbpy/data/utils/tests/test_dastcom5.py @@ -59,6 +59,7 @@ def test_read_record(mock_open, mock_np_fromfile, mock_read_headers): ) +@pytest.mark.remote_data @mock.patch("sbpy.data.utils.dastcom5.os.makedirs") @mock.patch("sbpy.data.utils.dastcom5.zipfile") @mock.patch("sbpy.data.utils.dastcom5.os.path.isdir") @@ -76,6 +77,7 @@ def test_download_dastcom5_raises_error_when_folder_exists( ) +@pytest.mark.remote_data @mock.patch("sbpy.data.utils.dastcom5.urllib.request") @mock.patch("sbpy.data.utils.dastcom5.os.makedirs") @mock.patch("sbpy.data.utils.dastcom5.zipfile") @@ -89,6 +91,7 @@ def test_download_dastcom5_creates_folder( mock_makedirs.assert_called_once_with(dastcom5.SBPY_LOCAL_PATH) +@pytest.mark.remote_data @mock.patch("sbpy.data.utils.dastcom5.zipfile") @mock.patch("sbpy.data.utils.dastcom5.os.path.isdir") @mock.patch("sbpy.data.utils.dastcom5.urllib.request.urlretrieve")