Index Page
Double Precision Array Files (DAF)

Table of Contents


   Double Precision Array Files (DAF)
      Abstract
         Purpose
         Intended Audience
         References

   Introduction
      The DAF Format Concept
      Array Addresses
      Array Files and Linked Lists
      Read and Write Access
      File Handles

   DAF Organization
      Structure
         The File Record
         Comment Area
         Summary Records
         Name Records
         Element Records
      Extension to the DAF Format
         DAF Run-Time Binary File Format Translation

   DAF Subsystem Subroutines
      Opening and Closing Array Files
      Creating Array Files
      Adding Arrays
      Adding Arrays to Multiple Array Files
      Reordering Arrays
      Searching
      Searching Multiple Array Files
      Accessing Array Elements
      Updating Summaries and Names
      Buffering

   Designing a DAF
      Creating an Array File

   Appendix A --- Summary of DAF Routines
      SPICELIB (Fortran)
         Deprecated routines
      CSPICE (C)
         Deprecated routines
      Icy (IDL)
      Mice (MATLAB)

   Appendix B --- Revision History
         2017 MAR 22 by E. D. Wright, N. J. Bachman, and B. V. Semenov
         2013 MAY 30 by E. D. Wright.
         2008 JAN 17 by B. V. Semenov.
         2002 JAN 13 by B. V. Semenov.
         1994 JUL 12 by NAIF.




Top

Double Precision Array Files (DAF)





Last revised on 2017 MAR 22 by B. V. Semenov.



Top

Abstract




The Double Precision Array File architecture stores arrays of double precision data. The SPICE SPKs, CKs, and binary PCKs use the DAF architecture.



Top

Purpose



This document is a reference guide for the SPICE DAF subsystem. Here you'll find:

    -- A list of the subsystem's API (application programming interface) routines---these are the routines that may be called directly by SPICE-based user application code.

    -- Description of the DAF format.

    -- Discussions of concepts essential to understanding the correct use of the DAF subsystem.



Top

Intended Audience



This document is intended for users that require detailed knowledge of the DAF format, such as the SPK, binary PCK, and CK formats already mentioned. It is also intended for users of the SPICE library who wish to create their own DAF-based file formats.

Nominally, users of DAF will not need to understand the material presented in this document. For example, users of SPICE SPK and CKs who wish to read state vectors and pointing angles from those files will normally do so using only subroutines and programs designed specifically for those formats. These subroutines are documented in the NAIF spk.req and ck.req Required Reading files.



Top

References



The following NAIF documents contain material closely related to the subject of this document.

    1. SPK Required Reading (spk.req)

    This document describes how the DAF structure is used in making the SPICE Satellite Planet Kernel (SPK) containing trajectory and ephemeris data.

    2. CK Required Reading (ck.req)

    This document describes how the DAF structure is used in making the SPICE C Kernel (CK) containing spacecraft or instrument orientation (pointing).

    3. PCK Required Reading (pck.req)

    This document describes how the DAF structure is used to store data in binary SPICE PCK.

    4. SPC Required Reading (spc.req)

    This document describes how labels, descriptive text and other comments may be added to or removed from a DAF.

    5. SPY User's Guide

    This document describes the use of the "spy" utility to check DAF-based SPK integrity, dump SPK data, dump SPK records, dump the contents of the SPK comment area. Standard Toolkit distributions do not include "spy," download the executable and User's Guide at the URL http://naif.jpl.nasa.gov/naif/utilities.html.



Top

Introduction





DAF---which stands for `Double precision Array File'---is a file architecture that provides the advantages of arrays and direct access files without incurring the disadvantages of either one.

This architecture is supported by a set of subroutines, part of the NAIF Toolkit software library.

Only the SPICELIB Toolkits include the full set of DAF APIs; Fortran serves as the ground state language. The CSPICE, Icy (IDL), and Mice (Matlab) Toolkit have a subset of the API set. This document will note those routines available only in Fortran SPICELIB and those available in the other language distributions.

A DAF can contain any number of double precision arrays. Each of these arrays can contain an arbitrary number of elements. Because DAF files are intended to be portable, the DAF design requires that the array elements must be `pure' double precision numbers. That is, they may not contain equivalenced or encoded integer or character values.

The DAF architecture assumes one byte size characters, four byte size integers, eight byte size double precision. DAFs created using SPICE libraries compiled with other size values may work if the relative size ratio between the data types remains 1-4-8.

The DAF subroutines in SPICE support the following operations:

    1. Create, open, or close a DAF.

    2. Add a new array to a file.

    3. Locate an array within a file, either by index or by using descriptive information about the array.

    4. Access---that is, retrieve or update---any contiguous set of elements in an array.

    5. Convert a binary (direct access) DAF to an equivalent SPICE transfer file, suitable for transfer to an environment using a form of binary representation different from that of the source CPU.

    6. Convert a DAF in SPICE transfer format into an equivalent binary file.

The last two functions make DAFs portable to any environment that supports ANSI Standard Fortran-77.



Top

The DAF Format Concept




The DAF architecture design intends each array contained in a particular DAF possess a `descriptive summary' of itself. The information making up the summary and the organization of the summary should be the same for each array in the DAF. The descriptive summary is composed of double precision and integer components. The number of double precision components, ND, and the number of integer components, NI, making up the array summaries, determine a particular format within the DAF architecture.

Values for ND and NI are fixed at the time a DAF is created. Any two DAFs that have the same values for ND and NI can be thought of as having the same `format'. (This does not guarantee that the arrays in the files contain the same kinds of information, only that they could be stored in the same file.) The values selected for ND and NI must satisfy the following inequalities:

        (NI + 1)                     (Note that this is
   ND + -------- <= 125               integer division.
            2                         That is, (NI + 1)/2
                                      is rounded down to
                                      the nearest integer.)
 
   0 <= ND <= 124
 
   2 <= NI <= 250
Each array stored in a DAF is `described', in part, by ND double precision numbers and NI integer numbers, which are stored separately from the array. Most of the details of this `description'---how many numbers are needed, and what they contain---are left to the designer of a specific DAF format.

The double precision numbers could include limits (the smallest and largest values in an array), a range of epochs throughout which the elements may be used, or statistics (the mean, median, and standard deviation of the elements).

The integer numbers could include contextual information (case number, identification codes for related objects or arrays) and conditional information (flags to indicate whether the array is unsorted, sorted by increasing or decreasing magnitude, or marked for deletion). Some integer numbers are used to keep track of the location of the array within the file.

Each array in a DAF is further described by NC characters of alphanumeric information. Examples of this alphanumeric information are producer names, archive codes, historical information, or anything else that is not easily encoded as double precision or integer numbers.

NC is a function of ND and NI. The relationship between NC and user-specified ND and NI was chosen to allowing a reasonable amount of space for storing the alphanumeric information for an array. NC is defined below:

                      (NI + 1)
   NC  =   8 * ( ND + -------- )     (Note that this is
                          2           integer division.)
Using an SPK as an example with NI = 6, ND = 2, then NC = 40.

The double precision and integer numbers that describe each array are `packed', or equivalenced, into an auxiliary double precision array before they are stored in the file. This auxiliary array is called the `summary' of the associated array. The individual (unpacked) numbers are called the `components' of the summary.

(The first ND elements of the summary contain the double precision components of the summary. Each of the remaining elements contains a pair of integer components. If NI is odd, the final element of the summary contains a single integer component.)

The NC alphanumeric characters that further describe each array are stored in a single character string, called the `name' of the array.



Top

Array Addresses




The location of each array in a DAF is defined by a pair of numbers, called the `initial address' and `final address' of the array.

The term `address' refers to a particular way of looking at an array file. Every DAF is actually a standard Fortran-77 direct access file, with a particular record length. (Every DAF has the same record length.) Each record is capable of storing up to 128 double precision numbers.

It is convenient, however, to think of a DAF as a numbered collection of slots named `words'. Each word is large enough to hold one double precision number. Words 1 through 128 are located in the first record of the file; words 129 through 256 are located in the second record; and so on. The number of each word is called the `address' of the word within the file.

Any pair of addresses defines a contiguous set of words, which may fall within a single physical record or span a number of records. The elements of each array in a DAF are stored in just such a set. The address of the first array element is the `initial address' of the array. The address of the final array element is the `final address' of the array.

The initial and final addresses of an array are always the values of the final two integer components of the summary for the array.



Top

Array Files and Linked Lists




It is a simplification, but a useful one, to say that the arrays in an array file form a doubly-linked list. Each new array added to a file is placed at the tail of this list.

Because the list is doubly-linked, the head and tail of the list can be located immediately. The arrays can be located by moving a pointer through the list, in either direction, one array at a time.

At any time, the summary and name of the array at which the pointer is currently pointing can be retrieved and examined to determine whether the array is of interest. If it is, the initial and final addresses (the final two integer components of the summary) may be used to access---retrieve or update---the entire array, or any contiguous set of elements therein.

For example, if BEGIN and END are the initial and final addresses of an array, the first ten elements of the array can be retrieved by asking for the elements stored in addresses BEGIN through BEGIN+9. If the array contains an odd number of elements, the middle element can be retrieved by asking for the element stored in address (BEGIN+END)/2.



Top

Read and Write Access




Array files may be opened for two kinds of access: read and write. A file opened for read access cannot be changed, either by adding a new array or by updating an existing one. Unless one of these operations must be performed, files should be opened for read access. The protection provided to files opened for read access is independent of any particular operating system.

A program may open only one DAF at a time for write access. When a program attempts to open a file for write access, an error is signaled if another file is already open for write access, or if the file is already open for read access. An error is also signaled if a program attempts to open a file for read access if the file is already open for write access. (Errors are signaled through the standard SPICE error handling mechanism.)



Top

File Handles




When a file is opened for either kind of access, it is assigned an integer `handle'. A mapping between handles and Fortran logical units is maintained internally by the DAF subroutines.

As a means of accessing files, handles have two advantages over logical unit numbers.

    1. They reduce the possibility that two or more program units of the same program will interfere with each other when both need to access the same DAF. When a program opens a DAF for the first time, the file is connected to a logical unit, and the unit is mapped to a handle. If the program attempts to open the same file again, the handle is returned immediately, and a counter is incremented. The file is not disconnected from the logical unit until it has been closed as many times as it has been opened. (This is analogous to the creation of multiple links to a single file under the UNIX operating system.) Any one program unit is prevented from releasing a file that is still being used by other program units.

    2. They allow the SPICE subroutines to prevent files opened for read access from being modified. (Positive handles are assigned to files opened for read access, negative handles to files opened for write access. Any attempt to modify a file with a positive handle signals an error.) Note that this scheme is independent of any file protection provided by the host operating system.



Top

DAF Organization







Top

Structure




Every DAF is a Fortran-77 direct access file, created by the following statement (or an equivalent C statement producing the same results):

   OPEN ( UNIT   = unit,
          FILE   = file name,
          ACCESS = 'DIRECT',
          RECL   = record length,
          STATUS = 'NEW'           )
The DAF will have binary format (big-endian, little endian, etc.) based on the architecture of the machine used to create the DAF.

The record length is processor dependent. The smallest possible value should be selected by the user such that each record in the file is large enough to contain 128 double precision numbers (1024 bytes) or 1000 characters, whichever is larger.

As of this version of the Toolkit, an expectation exists that a character has a size of one byte.

A DAF contains five types of physical records:

    1. A single `file record'. This contains global information about the file.

    2. An arbitrary number of `reserved records' for use as the comment area. NAIF recommends against use of the DAF reserved records routines. Rather, use the DAF comment area routines to store data information, file notes, or meta data.

    3. Some number of `summary records'. These contain array summaries and pointers to other summary records. The number of summary records in a particular array file is a function of the number of arrays stored in the file.

    4. Some number of `name records'. These contain array names. A DAF contains one name record for each summary record.

    5. An arbitrary number of `element records'. These contain elements of the arrays stored in the DAF.



Top

The File Record



The file record is always the first physical record in a DAF. The record size is 1024 bytes (for platforms with one byte char size, and four bytes integer size). The items listed in the File Record:

    1. LOCIDW (8 characters, 8 bytes): An identification word (`DAF/xxxx').

    The 'xxxx' substring is a string of four characters or less indicating the type of data stored in the DAF file. This is used by the SPICELIB subroutines to verify that a particular file is in fact a DAF and not merely a direct access file with the same record length. When a DAF is opened, an error signals if this keyword is not present. [Address 0]

    2. ND ( 1 integer, 4 bytes): The number of double precision components in each array summary. [Address 8]

    3. NI ( 1 integer, 4 bytes): The number of integer components in each array summary. [Address 12]

    4. LOCIFN (60 characters, 60 bytes): The internal name or description of the array file. [Address 16]

    5. FWARD ( 1 integer, 4 bytes): The record number of the initial summary record in the file. [Address 76]

    6. BWARD ( 1 integer, 4 bytes): The record number of the final summary record in the file. [Address 80]

    7. FREE ( 1 integer, 4 bytes): The first free address in the file. This is the address at which the first element of the next array to be added to the file will be stored. [Address 84]

    8. LOCFMT ( 8 characters, 8 bytes): The character string that indicates the numeric binary format of the DAF. The string has value either "LTL-IEEE" or "BIG-IEEE." [Address 88]

    9. PRENUL ( 603 characters, 603 bytes): A block of nulls to pad between the last character of LOCFMT and the first character of FTPSTR to keep FTPSTR at character 700 (address 699) in a 1024 byte record. [Address 96]

    10. FTPSTR ( 28 characters, 28 bytes): The FTP validation string.

    This string is assembled using components returned from the SPICELIB private routine ZZFTPSTR. [Address 699]

    11. PSTNUL ( 297 characters, 297 bytes): A block of nulls to pad from the last character of FTPSTR to the end of the file record. Note: this value enforces the length of the file record as 1024 bytes. [Address 727]

Example; display the octal and ASCII output for the first 1024 bytes of an SPK, little-endian:

   $ od -cbv -N1024 de421.bsp
 
   -c       display ASCII character or backslash escapes
   -b       display octal values
   -v       display duplicate lines
   -N1024   display 1024 bytes
 
   0000  D   A   F   /   S   P   K     002  \0  \0  \0 006  \0  \0  \0
         104 101 106 057 123 120 113 040 002 000 000 000 006 000 000 000
   0020   N   I   O   2   S   P   K
         116 111 117 062 123 120 113 040 040 040 040 040 040 040 040 040
   0040
         040 040 040 040 040 040 040 040 040 040 040 040 040 040 040 040
   0060
         040 040 040 040 040 040 040 040 040 040 040 040 040 040 040 040
   0100                                                 004  \0  \0  \0
         040 040 040 040 040 040 040 040 040 040 040 040 004 000 000 000
   0120  004  \0  \0  \0 325 005      \0   L   T   L   -   I   E   E   E
         004 000 000 000 325 005 040 000 114 124 114 055 111 105 105 105
   0140  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0160  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0200  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0220  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0240  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0260  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0300  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0320  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0340  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0360  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0400  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0420  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0440  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0460  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0500  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0520  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0540  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0560  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0600  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0620  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0640  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0660  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0700  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0720  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0740  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   0760  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1000  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1040  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1060  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1100  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1120  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1140  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1160  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1200  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1220  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1240  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1260  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0   F   T   P   S   T
         000 000 000 000 000 000 000 000 000 000 000 106 124 120 123 124
   1300   R   :  \r   :  \n   :  \r  \n   :  \r  \0   : 201   : 020 316
         122 072 015 072 012 072 015 012 072 015 000 072 201 072 020 316
   1320   :   E   N   D   F   T   P  \0  \0  \0  \0  \0  \0  \0  \0  \0
         072 105 116 104 106 124 120 000 000 000 000 000 000 000 000 000
   1340  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1360  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1400  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1420  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1440  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1460  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1500  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1520  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1540  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1560  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1600  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1620  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1640  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1660  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1700  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1720  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1740  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   1760  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
         000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
   2000
The "spy" utility can output an easier-to-read-by-humans form of the file record:

   Spy > dump file record spk de421.bsp;
 
   File Record Contents of SPK File de421.bsp
   ==================================================================
    File Architecture      :  DAF
    Binary File Format     :  LTL-IEEE
    FTP Validation String  :  Present and Intact
    Internal File Name     :  NIO2SPK
    ID Word                :  DAF/SPK
    ND                     :  2
    NI                     :  6
    Forward Record Pointer :  4
    Backward Record Pointer:  4
    First Free Address     :  2098645
   ==================================================================


Top

Comment Area



Any DAF can contain a number of reserved records for use as a comment area. The number of records defines the size of the comment area and is assigned when creating the DAF. The comment area of an existing DAF may be modified either by adding additional text or deleting the area's contents.

The DAF subsystem includes routines to programmatically manipulate reserved records. NAIF recommends against use of these routines, rather use those routines designed to manipulate the DAF comment area.

NAIF also provides utilities to manipulate a DAF comment area. Refer to the commnt User's Guide (commnt.ug) and spacit User's Guide (spacit.ug) for relevant information.



Top

Summary Records



A summary record contains a maximum of 128 double precision words. The first three words of each summary record are reserved for the following control information:

    1. The record number of the next summary record in the file. (Zero if this is the final summary record.)

    2. The record number of the previous summary record in the file. (Zero if this is the initial summary record.)

    3. The number of summaries stored in this record.

The record pointers form the basis of the array list. Each summary record is linked to two other summary records, allowing the summaries to be retrieved in forward or backward order. (The links between adjacent summaries in a summary record are implicit.) The names can be retrieved from the corresponding name records. And the locations (initial and final addresses) of the arrays themselves are stored in the summaries.

Although the control items are integer values, they are stored as double precision numbers. This allows summary records and element records, which contain only double precision numbers, to be buffered using the same mechanism.

The control items are followed immediately by the summaries themselves. The number of summaries (NS) that can fit in a single summary record depends on the size of a single summary (SS), a function of NI and ND:

                    (NI + 1)
   SS       =  ND + --------         (Note that this is
                        2             integer division.)
 
   SS * NS <=  125
 
   NS      <=  125/SS                (Note that NS must be an
                                      integer greater than or
                                      equal to one.)
Using an SPK as an example with NI = 6, ND = 2, then SS = 5.

A summary record can be depicted as written below, where the numbers correspond to the number of the double precision word in the record.

   -------------------------------------------------------------
   | 1 | 2 | 3 | 4 | 5 | 6 |       ...       | 126 | 127 | 128 |
   -------------------------------------------------------------
     ^   ^   ^
   NEXT  |   |
        PREV |
            NSUM
If SS is the size (in double precision words) of each summary array, then the first summary is stored in words 4 through SS+3; the second summary is stored in words SS+4 through 2(SS)+3; and so on. For example, if SS is equal to 3, 41 (125/3) summaries can fit in the summary record, leaving two words empty. In this case the record can be pictorially represented as written below, where the label below the record indicates the summary number.

   -------------------------------------------------------------
   | 1 | 2 | 3 | 4 | 5 | 6 | ... | 124 | 125 | 126 | 127 | 128 |
   -------------------------------------------------------------
     ^   ^   ^ { Summary 1 } ... {    Summary 41   }  ^     ^
   NEXT  |   |                                        |     |
        PREV |                                       These words
            NSUM                                     are unused.
Unlike arrays, summaries are never split across physical record boundaries, so the end of each summary record may remain unused. Whenever the number of summaries stored in the current summary record reaches the maximum number that will fit, a new (empty) summary record is added to the end of the file.

It is now clear that the bounds on the values for ND and NI are determined by their relation to the number of double precision words used for summary information in the summary record. ND and NI must satisfy the following inequalities:

        (NI + 1)                     (Note that this is
   ND + -------- <= 125               integer division.)
            2
 
   0 <= ND <= 124
 
   2 <= NI <= 250


Top

Name Records



Each name record contains nothing but array names. A new name record is added to the file each time a new summary record is added. The new name record is located in the record immediately following the new summary record. Because a DAF is written in this manner, the number of summary records is equal to the number of name records.

Each time a new summary is added to a summary record, a new name is added to the corresponding name record. Therefore, the number of summaries in a summary record is equal to the number of names in the corresponding name record.

If the numbers in the summary record represent double precision words, and the numbers in the name record represent characters, the two records can be depicted as written below for a DAF whose format is specified by ND = 2 and NI = 2.

   -------------------------------------------------------------
   | 1 | 2 | 3 | 4 | 5 | 6 | ... | 124 | 125 | 126 | 127 | 128 |
   -------------------------------------------------------------
     ^   ^   ^ { Summary 1 } ... {    Summary 41   }  ^     ^
   NEXT  |   |                                        |     |
        PREV |                                     Words 127 and
            NSUM                                   128 are unused.
 
   -------------------------------------------------------------
   | 1 |...| 24 |.......| 961 | ... | 984 | 985 |.......| 1000 |
   -------------------------------------------------------------
   {   Name 1   }.......{    Name 41      }  ^              ^
                                             |              |
                                           Characters 985 through
                                           1000 are unused.
The first name is stored in characters 1 through NC of the record; the second name is stored in characters NC+1 through 2(NC); and so on.



Top

Element Records



Most of the records in any DAF are element records. Element records hold the elements of the arrays stored in the file. (The other records are used for accounting purposes only.)

Each element record contains up to 128 double precision numbers. An element record is always full (contains 128 numbers) unless it immediately precedes a summary record, in which case it may be partially filled.

The elements stored in a particular element record may belong to more than one array. However, elements belonging to the same array are stored contiguously within the record.

For example, suppose three arrays exist: A, B, and C. Array A has 10 elements, array B has 100 elements, and array C has 15 elements. If all of the elements are stored in the same element record, it could be pictorially represented as written below:

   A[1]
   A[2]
   A[3]
    .
    .
    .
   A[10]
   B[1]
   B[2]
   B[3]
    .
    .
    .
   B[100]
   C[1]
   C[2]
   C[3]
    .
    .
    .
   C[15]
A particular element record always lies between two summary/name record pairs, or between a summary/name record pair and the end of the file.



Top

Extension to the DAF Format




NAIF modified the DAF specification for the N0052 release of the SPICE Toolkit (January, 2002). The modifications added the integrity string, the architecture strings, and the capability for DAF subsystem routines to perform run-time byte order translation.



Top

DAF Run-Time Binary File Format Translation



On supported platforms, the DAF readers are able to read DAFs (SPK, CK and binary PCK) written using a non-native, binary representation. This access is read-only; any operations requiring writing to the file (adding information to the comment area, or appending additional ephemeris data, for example) require prior conversion of the file to the native binary file format. See the Convert User's Guide (convert.ug) or the BINGO User's Guide for details (standard Toolkit distributions do not include "bingo," download the executable and User's Guide at the URL http://naif.jpl.nasa.gov/naif/utilities.html.)



Top

DAF Subsystem Subroutines





SPICE contains a set of routines usable to create, populate, and manipulate DAFs. A complete list of the routines can be found at the end of this document (Appendix A).

Each subroutine is prefaced by a complete SPICE module header that describes inputs, outputs, restrictions, and exceptions, discusses the context in which the subroutine should be used, and shows typical examples of its use. Any discussion of the subroutines in this article is intended as an introduction: the final documentation for any subroutine is its module header.



Top

Opening and Closing Array Files




An existing DAF can be opened by supplying the name of the file to DAFOPR (for read access) or DAFOPW (for write access). Each routine returns a file handle, which must be used for all subsequent access to the file.

SPICELIB (Fortran)

   CALL DAFOPR ( FNAME, HANDLE )          { Open for read }
   CALL DAFOPW ( FNAME, HANDLE )          { Open for write }
CSPICE (C)

   dafopr_c ( fname, &handle )
   dafopw_c ( fname, &handle )
Icy (IDL)

   cspice_dafopr, fname, handle
   cspice_dafopw, fname, handle
Mice (MATLAB)

   handle = cspice_dafopr( fname )
   handle = cspice_dafopw( fname )
Once opened, a DAF MUST be closed by supplying its handle to DAFCLS.

SPICELIB (Fortran)

   CALL DAFCLS ( HANDLE )                 { Close }
CSPICE (C)

   dafcls_c ( handle )
Icy (IDL)

   cspice_dafcls, handle
Mice (MATLAB)

   cspice_dafcls( handle )


Top

Creating Array Files




A new DAF can be created by supplying the name of the file, the type of data in the file, values for ND and NI, an internal file name, and the number of records to be reserved. NI must be greater than or equal to 2. (For more information about the bounds on NI and ND see the subsection `Summary records'.)

   CALL DAFONW ( FNAME,                   { Open new }
                 FTYPE,
                 ND,
                 NI,
                 IFNAME,
                 RESV,
                 HANDLE  )
 
   This routine currently exists only in Fortran SPICELIB.
The internal name of a DAF is a string of up to 60 bytes, which may be used to characterize the contents of the file. Its primary value is that, being internal to the file, it remains unchanged when the file is transferred between environments.

Any number of records may be reserved at the front of a DAF. By definition, the contents of these records are invisible to DAF subroutines, and may contain any information that the user wishes to store in them.

Once created, a new DAF remains open for write access until explicitly closed.



Top

Adding Arrays




A new array can be added to an existing DAF by calling four routines: DAFPS, DAFBNA, DAFADA, and DAFENA.

First, the summary is packed by DAFPS, which requires two arrays containing the double precision and integer components of the summary. It also requires the values of ND and NI for the file.

   CALL DAFPS ( ND, NI, DC, IC, SUM )     { Pack summary }
 
   This routine currently exists only in Fortran SPICELIB.
   \literal
 
   The final two integer components of the summary are
   always used to store the initial and
   final addresses of the array imposing that NI be
   greater than or equal to two. These components are
   filled in after the array has been
   stored: any values for these components
   supplied by the user are ignored.
 
 
   Next, the new array must be initialized by calling
   DAFBNA. DAFBNA requires the handle of the file
   (which must be open for write access),
   the array name, and the array summary.
 
   \literal
   CALL DAFBNA ( HANDLE, SUM, NAME )      { Begin new array }
 
   This routine currently exists only in Fortran SPICELIB.
The elements of the array are added by DAFADA. The elements may be supplied using one call,

   CALL DAFADA ( DATA, N )                { Add data to array }
 
   This routine currently exists only in Fortran SPICELIB.
or in any number of installments,

   DO WHILE ( MORE )
       ...
      CALL DAFADA ( DATA, N )             { Add data to array }
   END DO
Once the entire array has been supplied, DAFENA makes the addition permanent.

   CALL DAFENA                            { End new array }
 
   This routine currently exists only in Fortran SPICELIB.
If the process is aborted before DAFENA is called, the summary and name are not stored, and the new array does not become a permanent member of the file. Space allocated for elements of the array cannot be removed from the file; however, it will be overwritten by the elements of the next array added to the file.

One way to abort the addition of an array to a file is to call DAFBNA to start a new array in the same file, without first ending the current array.



Top

Adding Arrays to Multiple Array Files




It is possible to add data to arrays in multiple files in an interleaved fashion: addition of data to an array in one file can be interrupted in order to add data to an array in another file. To accomplish this, it is necessary to tell DAFADA and DAFENA which file to act upon. This file is called the `current file'.

When DAFBNA is used to begin an array, the file specified by the handle passed to DAFBNA becomes the current file. Calls to DAFADA or DAFENA will add data to or end the last array begun in this file. If DAFBNA is called again, this time with a different handle, the file specified by that handle becomes current. Files that are not current are not affected in any way by beginning, adding data to, or ending arrays in the current file.

In any given file, an array that is in progress---that is, an array begun by DAFBNA but not yet ended by DAFENA---is called the `current array' for that file. No file can have more than one current array.

In order to continue or end an array in a file that is no longer current, the file in question is selected as the current file by a call to DAFCAD:

   CALL DAFCAD ( HANDLE )                { DAF, continue adding data }
 
   This routine currently exists only in Fortran SPICELIB.
After this call, the file identified by HANDLE will be the current file, and calls to DAFADA will add data to the current array in this file. The usual sequence of calls has the form:

   CALL DAFCAD ( HANDLE  )               { DAF, continue adding data }
   CALL DAFADA ( DATA, N )               { DAF, add data to array }
Since DAFENA can be used to end arrays only in the current file, DAFCAD is also used to select a file as current so that an array can be ended in that file:

   CALL DAFCAD ( HANDLE  )               { DAF, continue adding data }
   CALL DAFENA                           { DAF, end new array }
Only files that already have an array in progress may be selected as current by DAFCAD. An error will be signaled if DAFCAD is used to select a DAF that does not have an array in progress.

The following example illustrates the use of DAFCAD:

We write data obtained from the routine GET_DATA (which is not a SPICELIB routine) into two separate DAFs. The first N/2 elements of the array DATA will be written to the first file; the rest of the array will be written to the second file.

Open the DAFs for write access, using either DAFOPW (if the files already exist) or DAFONW (if they do not).

   CALL DAFOPW ( FNAME1, HANDL1 )
   CALL DAFOPW ( FNAME2, HANDL2 )
Begin the new DAFs by calling DAFBNA.

   CALL DAFBNA ( HANDL1, SUM1, NAME1 )
   CALL DAFBNA ( HANDL2, SUM2, NAME2 )
Add data to the arrays, using DAFCAD to select the current file and DAFADA to add data to the current array in the current file.

   CALL GET_DATA ( DATA, N, FOUND )
 
   DO WHILE ( FOUND )
 
      CALL DAFCAD   ( HANDL1                          )
      CALL DAFADA   ( DATA,               N/2         )
 
      CALL DAFCAD   ( HANDL2                          )
      CALL DAFADA   ( DATA( N/2 + 1 ),    N - N/2     )
 
      CALL GET_DATA ( DATA, N, FOUND )
 
   END DO
End each array by calling DAFENA, selecting the file in which to end the array by calling DAFCAD:

   CALL DAFCAD ( HANDL1 )
   CALL DAFENA
 
   CALL DAFCAD ( HANDL2 )
   CALL DAFENA
The notions of `current DAF' and `current array' apply to both adding data to arrays and to searching DAFs. However, the files and arrays regarded as current for the purpose of searching are unrelated to those regarded as current for the purpose of adding data.



Top

Reordering Arrays




Once arrays are written to a DAF, it is conceivable that their order may need to be changed. Suppose that the arrays in a DAF are to be ordered according to the arithmetic mean of the data they contain. Also suppose that the arithmetic mean of data in an array is stored in the second double precision component of the summary. After reading each summary and creating a vector IORDER with dimension N that specifies the new order of the arrays, the subroutine DAFRA can be used to reorder the arrays.

   CALL DAFRA ( HANDLE, IORDER, N )       { Reorder arrays }


Top

Searching




The process of locating an array of interest within an array file is known as `searching'. The organization of the arrays as a doubly-linked list makes it possible to conduct searches in forward or backward order.

The complete set of DAF routines that act on the current file (for searching) is:

   DAFFNA                                 { DAF, find next array }
   DAFFPA                                 { DAF, find previous array }
   DAFGS                                  { DAF, get summary }
   DAFGN                                  { DAF, get name }
   DAFGH                                  { DAF, get handle }
   DAFRS                                  { DAF, replace summary }
   DAFRN                                  { DAF, replace name }
   DAFWS                                  { DAF, write summary }
Subroutines DAFBFS and DAFFNA are used to search a DAF in forward order. DAFBFS places a pointer at the head of the doubly-linked list formed by the arrays in the file. Each call to DAFFNA moves the pointer to the next array in the list. (The first call to DAFFNA moves the pointer to the first array.) DAFFNA returns a logical flag which is true whenever another array has been found, and is false when the tail of the list has been reached. All forward searches are variations on the following template:

SPICELIB (Fortran)

   CALL DAFBFS ( HANDLE )                 { Begin forward search }
   CALL DAFFNA ( FOUND  )                 { Find next array }
 
   DO WHILE ( FOUND )
       ...
      CALL DAFFNA ( FOUND )               { Find next array }
   END DO
CSPICE (C)

   dafbfs_c ( handle );
   daffna_c ( &found );
 
   while ( found )
      {
       ...
      daffna_c ( &found );
      }
Icy (IDL)

   cspice_dafbfs, handle
   cspice_daffna, found
 
   while found do begin
       ...
      cspice_daffna, found
   endwhile
Mice (MATLAB)

   cspice_dafbfs( handle )
   found = cspice_daffna
 
   while found
       ...
      found = cspice_daffna
   end
Subroutines DAFBBS and DAFFPA are likewise used to search a DAF in backward order. DAFBBS moves the pointer to the tail (instead of the head) of the list; DAFFPA moves the pointer to the previous (instead of the next) array in the list. The template shown above is modified to conduct backward searches by replacing calls to DAFBFS and DAFFNA with calls to DAFBBS and DAFFPA, respectively:

SPICELIB (Fortran)

   CALL DAFBBS ( HANDLE )                 { Begin backward search }
   CALL DAFFPA ( FOUND  )                 { Find previous array }
 
   DO WHILE ( FOUND )
       ...
      CALL DAFFPA ( FOUND )               { Find previous array }
   END DO
CSPICE (C)

   dafbbs_c ( handle );
   daffpa_c ( &found );
 
   while ( found )
      {
       ...
      daffpa_c ( &found );
      }
Icy (IDL)

   cspice_dafbbs, handle
   cspice_daffpa, found
 
   while found do begin
       ...
      cspice_daffpa, found
   endwhile
Mice (MATLAB)

   cspice_dafbbs( handle )
   found = cspice_daffpa
 
   while found
       ...
      found = cspice_daffpa
   end
Once a search has begun, the pointer may be moved in either direction.

After the pointer has been moved to a new array, the summary and name of the array can be retrieved by DAFGS and DAFGN. Once returned, a name can be examined directly. However, a summary must may need to be unpacked into its components by subroutine DAFUS.

   CALL DAFBBS ( HANDLE )                 { Begin backward search }
   CALL DAFFPA ( FOUND  )                 { Find previous array }
 
   DO WHILE ( FOUND )
      CALL DAFGS ( SUM  )                 { Get summary }
      CALL DAFUS ( SUM, ND, NI, DC, IC )  { Unpack summary }
      CALL DAFGN ( NAME )                 { Get name }
       ...
      CALL DAFFNA ( FOUND )               { Find next array }
   END DO
CSPICE (C)

   dafbfs_c ( handle );
   daffna_c ( &found );
 
   while ( found )
      {
      dafgs_c ( sum  );
      dafus_c ( sum, ND, NI, dc, ic );
      dafgn_c ( name );
       ...
      daffna_c ( &found );
      }
The Icy (IDL) and Matlab (Mice) implementations of the dafgs_c interface do not require an explicit call to unpack the summary. I.e., a call to cspice_dafgs equates to the C calls:

   dafgs_c( sum );
   dafus_c( sum, nd, ni, dc, ic );
without use of the 'sum' variable.

Icy (IDL)

   cspice_dafbfs, handle
   cspice_daffna, found
 
   while found do begin
      cspice_dafgs, ND, NI, dc, ic
      cspice_dafgn, name
       ...
      cspice_daffna, found
   endwhile
Mice (MATLAB)

   cspice_dafbfs( handle )
   found = cspice_daffna
 
   while found
      [dc, ic ] = cspice_dafgs( ND, NI );
      name = cspice_dafgn
       ...
      found = cspice_daffna
   end


Top

Searching Multiple Array Files




Searching multiple DAFs simultaneously is a little like adding data to multiple files simultaneously: in each case, it becomes necessary to identify the file to act upon, when calling routines that don't accept an input handle argument.

As with adding data, the notions of `current DAF' and `current array' apply to searching. Starting a search in an array file by calling either DAFBFS or DAFBBS makes that file the `current file'. Subsequent calls to DAFFNA or DAFFPA advance or back up the array pointer in the current file. The last array found by DAFFNA or DAFFPA in the `current file' is the `current array' for that file. As mentioned above, there is no relation between the files or arrays that are considered current for searching and those considered current for adding data.

If, after a search is started in one DAF, DAFBFS or DAFBBS are called to start a search in a second DAF, the second file becomes current: DAFFNA, DAFFPA, DAFGN, and DAFGS will all operate on the second file.

The routine DAFCS is used to continue a search in a DAF that is no longer current. Calling DAFCS makes the file specified by the input handle argument the current file for searching:

   CALL DAFCS  ( HANDLE )                 { DAF, continue search }
After this call, the routines in the above list will act upon the file designated by HANDLE. For example, to continue a forward search in that file,

   CALL DAFCS  ( HANDLE )                 { DAF, continue search }
   CALL DAFFNA ( FOUND  )                 { DAF, find next array }
and to continue a backward search,

   CALL DAFCS  ( HANDLE )                 { DAF, continue search     }
   CALL DAFFPA ( FOUND  )                 { DAF, find previous array }
while to get the name and summary of the current array in the file,

   CALL DAFCS ( HANDLE )                  { DAF, continue search }
   CALL DAFGN ( NAME )                    { DAF, get name }
   CALL DAFGS ( SUM  )                    { DAF, get summary }
A search must have been started by DAFBFS or DAFBBS before it can be continued. An error will signal if DAFCS is used to continue a search in a DAF in which no search has been started.



Top

Accessing Array Elements




After an array of interest has been located, the entire array or any contiguous set of elements can be accessed---read or updated---by supplying a pair of addresses. Elements are read by DAFRDA and written by DAFWDA.

The following code fragment continues the example above by subtracting the average from each of the elements in the array. (Recall that IA and FA contain the initial and final addresses of the array.)

   CALL DAFRDA ( HANDLE, IA, FA, DATA )   { Read data
                                            from address }
   DO I = 1, FA - IA + 1
      DATA(I) = DATA(I) - MAXAVG
   END DO
 
   CALL DAFWDA ( HANDLE, IA, FA, DATA )   { Write data
                                            to address }
Note that it is not necessary to retrieve the entire array at once. The following code fragment illustrates how to process an array of unknown size using a fixed amount of local storage. The local array DATA is declared to be size CHUNK. DAFRDA reads a maximum of CHUNK elements from the double precision array and DAFWDA writes them. This technique is useful when the arrays stored in a DAF may be arbitrarily large.

   FIRST = IA
 
   DO WHILE ( FIRST .LE. FA )
      LAST  = MIN ( FA,     FIRST + CHUNK - 1 )
      CALL DAFRDA ( HANDLE, FIRST, LAST, DATA )   { Read data
                                                    from address }
      NUMELE = LAST - FIRST + 1
 
      DO I = 1, NUMELE
         DATA(I) = DATA(I) - MAXAVG
      END DO
 
      CALL DAFWDA ( HANDLE, FIRST, LAST, DATA )   { Write data
      FIRST = FIRST + CHUNK                         to address }
   END DO


Top

Updating Summaries and Names




In the previous example, once the average value of the array has been subtracted from each element of the array, the value for the average stored in the summary is no longer valid (the average is now zero) and should be changed.

Subroutines DAFRS and DAFRN are analogous to subroutines DAFGS and DAFGN. DAFGS `gets' the summary for the array to which the pointer currently points; DAFRS replaces it. DAFGN `gets' the name of the array to which the pointer currently points; DAFRN replaces it.

If the index, K, of the updated array is known, then the new average for the array (zero) is stored by the following code fragment.

In the code fragment below, we also update each array name by appending the string

   (new)
to the existing name.

   CALL DAFBFS ( HANDLE )                 { Begin forward search }
 
   DO I = 1, K
      CALL DAFFNA ( FOUND  )              { Find next array }
   END DO
 
   CALL DAFGS ( SUM )                     { Get summary }
   CALL DAFUS ( SUM, ND, NI, DC, IC )     { Unpack summary }
 
   DC(2) = 0.D0
 
   CALL DAFPS ( ND, NI, DC, IC, SUM )     { Pack summary }
   CALL DAFRS ( SUM )                     { Replace summary }
 
   CALL DAFGN  ( NAME )                   { Get name }
   CALL SUFFIX ( '(new)', 1, NAME )
   CALL DAFRN  ( NAME )                   { Replace name }


Top

Buffering




Unless the value of CHUNK is 128 (the number of double precision words in a record) and the initial address of the array happens to correspond to the first word of a physical record (neither of which is very likely), each call to DAFRDA or DAFWDA will involve reading partial records---data that spans across records. In general, successive calls will refer to different parts of at least one record.

In fact, as records are read from DAFs they are saved in an internal buffer maintained by the DAF subroutines. If any part of a record is needed, it can frequently be returned directly from the buffer, without accessing the file again. In particular, when an entire array is accessed sequentially, as in the example above, each of the necessary records is read exactly one time. When the elements of an array are accessed more randomly, the number of file accesses may increase somewhat.

It is possible, at any point in a program, to determine the number of file accesses prevented by the buffering scheme. The subroutine DAFNRR returns the number of physical records actually read, and the number of records or partial records that have been requested, as illustrated below:

   CALL DAFNRR ( READS, REQS )            { Number of reads,
                                            requests         }
   RATIO  = DBLE(READS) / DBLE(REQS)
   PERCNT = INT ( RATIO * 100.D0 )
   WRITE (*,*) 'Reads/requests (%) = ', PERCNT
Ideally, the ratio of reads to requests should approach zero. In the worst case, where it approaches one, the size of the buffer should probably be adjusted. (The module headers for DAFRDR and DAFWDR provide details on adjusting the buffer size. Please consult NAIF before altering the buffer size.)



Top

Designing a DAF







Top

Creating an Array File




The following example illustrates the use of addresses and lists within an DAF by showing how a simple array file might be created, and how arrays might be added to that file.

Throughout the example, the following notations will be used:

    -- Within the file record there are several values: IDWORD, ND, NI, RI, RF, and FFA. IDWORD is a character string that contains the file architecture, DAF, and code for the type of data stored in the DAF file. This code is a string consisting of four characters or less and is described in the header of the routine DAFONW. ND and NI are the values of the parameters that define the format of the file. RI and RF are the record numbers of the initial and final summary records in the file. FFA is the first free address in the file.

    -- Within a particular summary record, NEXT and PREV are the record numbers of the next and previous summary records in the file, and NSUM is the number of summaries stored in the record.

The first step in creating a file is to determine the name to be given to the type of data stored in the DAF file. For this example, the data type will be 'Xmpl'. For more information about the restrictions on the character string describing the type of data in the DAF file, see the header of the routine DAFONW. The IDWORD written to the new file is the concatenation of the string 'DAF/' with the data type string. So, for this example, the IDWORD written to the new file is 'DAF/Xmpl'.

The next step is to select values for ND and NI. Normally, these are relatively small, allowing several summaries to fit in each summary record and thus increasing the speed with which the file can be searched. A new file is opened by calling DAFONW, specifying the selected values for ND and NI. Recall that the final two integer components of any array summary---IC(NI-1) and IC(NI)---contain the initial and final addresses of the array, so NI must be at least 2.

The example will be easier to follow, however, if the number of summaries that can fit in a summary record is minimized. Therefore, in this example ND and NI will take on unusually large values:

   ND = 25
   NI = 27
Each array summary requires 39 double precision words of storage:

        (NI + 1)
   ND + -------- =  25 + 14 = 39
           2
Therefore, each summary record can hold 3 summaries:

   125 (words per record)
   -----------------------  =  3 (summaries per record)
    39 (words per summary)
If `Summary(i)[j]' represents the j'th element of the i'th summary array, then the layout of a typical summary record is shown below.

   Word     Value
   ----     ----------------
      1     NEXT
      2     PREV
      3     NSUM
      4     Summary( 1)[ 1]
      5     Summary( 1)[ 2]
             ...
     42     Summary( 1)[39]
     43     Summary( 2)[ 1]
             ...
     81     Summary( 2)[39]
     82     Summary( 3)[ 1]
             ...
    120     Summary( 3)[39]
    121     Unused
             ...
    128     Unused
The number of names that an array record can hold is equivalent to the number of summaries that the summary record can hold. In this example it's three.

Recall that NC, the maximum number of characters in an array name, is determined by the values of ND and NI. For this example, where ND = 25 and NI = 27, the value of NC is computed below:

                      (NI + 1)
   NC  =   8 * ( ND + -------- )  = 8 * ( 25 + 14 ) = 8 * 39 = 312
                          2
Each array name may use up to 312 characters of storage. An array name does not have to be exactly NC characters long. NC is simply the limit on the length of the array name.

If `Name(i)[j]' represents the j'th character of the i'th name, then the layout of a typical name record is shown below.

   Character    Value
   ---------    --------------
           1     Name( 1)[  1]
           2     Name( 1)[  2]
                  ...
         312     Name( 1)[312]
         313     Name( 2)[  1]
                  ...
         624     Name( 2)[312]
         625     Name( 3)[  1]
                  ...
         936     Name( 3)[312]
         937     Unused
                  ...
        1000     Unused
Assume that RESV, the number of reserved records, is 10. When DAFONW opens the new file, it stores the file record information in record 1, the reserved records in records 2 through 11, and the initial summary record in record 12. Because the file is empty, the initial summary record, RI, is also the final summary record, RF.

   RI = 12
   RF = 12
DAFONW stores the lone name record for the file immediately after the summary record, in record 13. Therefore the first free address, FFA, in the file is the first word in record 14:

   FFA = word + (record - 1) * 128
 
       =    1 + (14     - 1) * 128
 
       =    1 + 1664
 
       =    1665
DAFONW also writes the internal file name to the file record. For this example the internal file name will be 'TESTFILE'. For the rest of the example, the file record will be depicted as a collection of values enclosed by braces and preceded by a record number:

   r { IDWORD=x, ND=a, NI=b, IFNAME=c, RI=d, RF=e, FFA=f }
So, the file record for this example file is initially:

   1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                          RI=12, RF=12, FFA=1665           }
Because there is only one summary record, the values of NEXT and PREV in that record are both zero. Because the file contains no arrays, the value of NSUM is also zero. The information needed to create the summary record is complete. For the rest of the example, each summary record will be depicted as a collection of values enclosed by angle brackets and preceded by a record number:

   r < NEXT=a, PREV=b, NSUM=c, (d,e),(f,g),(h,i) >
The ordered pairs enclosed in parentheses are the initial and final addresses of the arrays whose summaries are contained in the record. The remaining components of each summary are ignored in order to make the example easier to follow. Thus, the lone summary record for this example file is initially:

   12 < NEXT=0, PREV=0, NSUM=0, (0,0),(0,0),(0,0) >
Name records will always be depicted as

   r < " " >
Element records will always be depicted as

   r < N >
where N is the number of elements stored in the record.

Once the initial summary and name records have been written, the file is complete, if uninteresting:

    1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                           RI=12, RF=12, FFA=1665           }
    2
    .
    . Records 2 through 11 are reserved records.
    .
   11
   12 < NEXT=0, PREV=0, NSUM=0, (0,0),(0,0),(0,0) >
   13 < " " >
Assume that an array A1, containing 100 elements, is to be added to the file. The array will be stored contiguously, beginning at the first free address. Thus, its initial and final addresses will be 1665 (start record 14, so 128 * 13 + 1) and 1764 ( 128 * 13 + 100), respectively. The entire array fits into a single record, so one element record will be added to the file. The value of NSUM in the summary record is incremented by one. The new value of FFA is the address following the final address of the new array: 1765. This is stored in the file record.

    1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                           RI=12, RF=12, FFA=1765           }
    2
    .
    . Records 2 through 11 are reserved records.
    .
   11
   12 < NEXT=0, PREV=0, NSUM=1, (1665,1764),(0,0),(0,0) >
   13 < " " >
   14 < 100 > 100 words for A1
Assume that a second array A2, containing 200 elements, is to be added to the file. The elements will be stored between addresses 1765 and 1964. The array will fill the remainder of the first element record, all of a second record, and part of a third, so two element records will be added to the file. The value of NSUM in the summary record is incremented again. And the new value of FFA (1965) is stored in the file record.

    1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                           RI=12, RF=12, FFA=1965           }
    2
    .
    . Records 2 through 11 are reserved records.
    .
   11
   12 < NEXT=0, PREV=0, NSUM=2, (1665,1764),(1765,1964),(0,0) >
   13 < " " >
   14 < 128 > 100 words for A1, 28 words for A2
   15 < 128 > 128 words for A2
   16 <  44 >  44 words for A2
To add a third array A3, containing 150 elements, the process is repeated. The elements will be stored between addresses 1965 and 2114. The array will fill the remainder of the third element record, and part of a fourth, so one new element record is added. The value of NSUM is in the summary record is incremented again. And the new value of FFA (2115) is in the file record.

    1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                           RI=12, RF=12, FFA=2115           }
    2
    .
    . Records 2 through 11 are reserved records.
    .
   11
   12 < NEXT=0, PREV=0, NSUM=3, (1665,1764),(1765,1964),(1965,2114) >
   13 < " " >
   14 < 128 > 100 words for A1, 28 words for A2
   15 < 128 > 128 words for A2
   16 < 128 >  44 words for A2, 84 words for A3
   17 <  66 >  66 words for A3
Note that the final summary record is full, so new summary and name records will added to the file. (Record 17 will remain only partially filled.) The values of NEXT and PREV in the summary records are adjusted so that the records point to each other:

    1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                           RI=12, RF=12, FFA=2115           }
    2
    .
    . Records 2 through 11 are reserved records.
    .
   11
   12 < NEXT=18, PREV=0, NSUM=3, (1665,1764),(1765,1964),(1965,2114) >
   13 < " " >
   14 < 128 > 100 words for A1, 28 words for A2
   15 < 128 > 128 words for A2
   16 < 128 >  44 words for A2, 84 words for A3
   17 <  66 >  66 words for A3
   18 < NEXT=0, PREV=12, NSUM=0, (0,0),(0,0),(0,0) >
   19 < " " >
The file record is updated so that the value of RF points to the new summary record, and the value of FFA in the file record will point to the first word in the first record following the new name record (address 2433):

    1 { IDWORD='DAF/Xmpl', ND=25, NI=27, IFNAME='TESTFILE',
                           RI=12, RF=18, FFA=2433           }
    2
    .
    . Records 2 through 11 are reserved records.
    .
   11
   12 < NEXT=18, PREV=0, NSUM=3, (1665,1764),(1765,1964),(1965,2114) >
   13 < " " >
   14 < 128 > 100 words for A1, 28 words for A2
   15 < 128 > 128 words for A2
   16 < 128 >  44 words for A2, 84 words for A3
   17 <  66 >  66 words for A3
   18 < NEXT=0, PREV=12, NSUM=0, (0,0),(0,0),(0,0) >
   19 < " " >
Adding more arrays is identical to the previous example: the necessary element records are added; the summary and name records are updated; and the value of FFA is updated. However, every third array also adds new summary and name records, and the values of RF and FFA are updated as well.



Top

Appendix A --- Summary of DAF Routines





Summary of Mnemonics

The following is a complete list of DAF API mnemonics and translations, in alphabetical order for each SPICE supported language.



Top

SPICELIB (Fortran)




A few of the routines listed are entry points of another routine. If a routine is an entry point, the parent routine's name will be listed inside brackets preceding the mnemonic translation.

Many of the subroutines listed here are not normally used except to support other subroutines. For example, because the subroutines that read and write records (DAFRCR, DAFRDR, DAFRFR, DAFWCR, DAFWDR, DAFWFR) are low level routines, they are not usually called by a typical user, but instead by higher level DAF routines.

   DAFAC                Add comments
   DAFADA [DAFANA]      Add data to array
   DAFAH                Assign handles
   DAFANA               Add new array
   DAFARR               Add reserved records
   DAFARW [DAFRWD]      Address to record/word
   DAFBBS [DAFFA]       Begin backward search
   DAFBFS [DAFFA]       Begin forward search
   DAFBNA [DAFANA]      Begin new array
   DAFBT                Convert binary file to transfer file
   DAFCAD [DAFANA]      Continue adding data
   DAFCLS [DAFAH]       Close an open DAF
   DAFCS  [DAFFA]       Continue search
   DAFDC                Delete comments
   DAFEC                Extract comments
   DAFENA [DAFANA]      End new array
   DAFFA                Find array
   DAFFNA [DAFFA]       Find next array
   DAFFNH [DAFAH]       File name to handle
   DAFFPA [DAFFA]       Find previous array
   DAFGDA               Read data from address
   DAFGDR [DAFRWD]      Get double precision record
   DAFGH  [DAFFA]       Get handle
   DAFGN  [DAFFA]       Get array name
   DAFGS  [DAFFA]       Get summary
   DAFGSR [DAFRWD]      Get summary/descriptor record
   DAFHFN [DAFAH]       Handle to file name
   DAFHLU [DAFAH]       Handle to logical unit
   DAFHOF [DAFAH]       Handles of open files
   DAFHSF [DAFAH]       Handle to summary format
   DAFLUH [DAFAH]       Logical unit to handle
   DAFNRR [DAFRWD]      Number of reads, requests
   DAFONW [DAFAH]       Open new DAF for write
   DAFOPR [DAFAH]       Open DAF for read
   DAFOPW [DAFAH]       Open DAF for write
   DAFPS                Pack summary
   DAFRA                Re-order arrays
   DAFRCR               Read character record
   DAFRDA               Read data from address
   DAFRFR               Read file record
   DAFRN  [DAFFA]       Change array name
   DAFRRR               Remove reserved records
   DAFRS  [DAFFA]       Replace summary
   DAFRWA               Record/word to address
   DAFRWD               Read, write double precision
   DAFSIH [DAFAH]       Signal invalid handles
   DAFTB                Convert transfer file to binary file
   DAFUS  [DAFPS]       Unpack summary
   DAFWCR               Write character record
   DAFWDA               Write data to address
   DAFWDR [DAFRWD]      Write double precision record
   DAFWFR               Write file record
   DAFWS  [DAFFA]       Write summary


Top

Deprecated routines



   DAFA2B               ASCII to binary
   DAFB2A               Binary to ASCII
   DAFB2T               Binary to text
   DAFOPN [DAFAH]       Open new
   DAFRDA               Read data from address
   DAFRDR [DAFRWD]      Read double precision record
   DAFT2B               Text to binary
DAFA2B, DAFB2A, DAFT2B, and DAFB2T were recommended for converting DAFs to the transfer format file. These routines are now obsolete; however, they will remain in SPICELIB for backwards compatibility. Use the routines DAFTB and DAFBT.

The routines DAFGDA and DAFGSR supersede DAFRDA.



Top

CSPICE (C)




   dafac_c              Add comments
   dafbbs_c             Begin backward search
   dafbfs_c             Begin forward search
   dafcls_c             Close
   dafcs_c              Continue search
   dafdc_c              Delete comments
   dafec_c              Extract comments
   daffna_c             Find next array
   daffpa_c             Find previous array
   dafgda_c             Read data from address
   dafgn_c              Get array name
   dafgs_c              Get summary
   dafgsr_c             Get summary/descriptor record
   dafopr_c             Open for read
   dafopw_c             Open for write
   dafps_c              Pack summary
   dafrda_c             Read data from address
   dafrfr_c             Read file record
   dafrs_c              Replace summary
   dafus_c              Unpack summary


Top

Deprecated routines



   dafrda_c             Read data from address


Top

Icy (IDL)




   cspice_dafac         Add comments
   cspice_dafbbs        Begin backward search
   cspice_dafbfs        Begin forward search
   cspice_dafcls        Close
   cspice_dafcs         Continue search
   cspice_dafdc         Delete comments
   cspice_dafec         Extract comments
   cspice_daffna        Find next array
   cspice_daffpa        Find previous array
   cspice_dafgda        Read data from address
   cspice_dafgn         Get array name
   cspice_dafgs         Get and unpack summary
   cspice_dafopr        Open for read
   cspice_dafopw        Open for write
   cspice_dafrs         Replace summary


Top

Mice (MATLAB)




   cspice_dafac         Add comments
   cspice_dafbbs        Begin backward search
   cspice_dafbfs        Begin forward search
   cspice_dafcls        Close
   cspice_dafcs         Continue search
   cspice_dafdc         Delete comments
   cspice_dafec         Extract comments
   cspice_daffna        Find next array
   cspice_daffpa        Find previous array
   cspice_dafgda        Read data from address
   cspice_dafgn         Get array name
   cspice_dafgs         Get and unpack summary
   cspice_dafopr        Open for read
   cspice_dafopw        Open for write


Top

Appendix B --- Revision History







Top

2017 MAR 22 by E. D. Wright, N. J. Bachman, and B. V. Semenov



Corrected small typo in fake Tex code that caused incorrect appearence of Appendix A in HTML format.

Updated code example to show calls to DAFGN and DAFRN.

Corrected miscellaneous typos throughout text. Corrected CSPICE cell function names.

Updated to point to SPY and BINGO User's Guides available from the NAIF server "Utilities" page.



Top

2013 MAY 30 by E. D. Wright.



Edits to conform to current NAIF standards for Required Reading documents.

The document now includes description of CSPICE, Icy, and Mice DAF APIs.



Top

2008 JAN 17 by B. V. Semenov.



Previous edits.



Top

2002 JAN 13 by B. V. Semenov.



Added a brief discussion of the DAF run-time binary file format translation capability now present in the SPICE Toolkit.



Top

1994 JUL 12 by NAIF.



The document differs from the previous version of September 1991 in that it includes the addition of new routines that should be used instead of existing SPICELIB routines. DAFONW replaces DAFOPN, DAFTB replaces DAFA2B and DAFT2B, and DAFBT replaces DAFB2A and DAFB2T. Also, the term to describe the non-binary DAF file, text, has been replaced with a more accurate term, transfer, indicating that the files are written in a format suitable for transfer from one platform to another.