 
Double Precision Array Files (DAF)
===========================================================================
 
   Last revised on 2008 JAN 17 by B. V. Semenov.
 
 
Abstract
--------------------------------------------------------
 
   Double Precision Array File, DAF, is an architecture for files that
   stores arrays of double precision data. The SPICE SPK, CK, and binary
   PCK files use the DAF architecture and associated software.
 
 
Note on FORTRAN and C Versions
--------------------------------------------------------
 
   This document covers the FORTRAN version of the interfaces of this
   subsystem. CSPICE provides f2c translated equivalents for all, and
   native C wrappers for some of them. If you wish to use the C versions of
   the interfaces described in this document, refer to the CSPICE Required
   Reading, cspice.req, for more information on naming conventions,
   locations, and usage of the f2c'ed routines and native C wrappers.
 
 
Purpose
--------------------------------------------------------
 
   This document describes the Double Precision Array File, DAF, an
   architecture for files that store arrays of double precision numbers.
   The SPICE SP-kernel and C-kernel files use the DAF architecture and
   associated software. The Required Reading files for these two SPICE
   kernels refer to this document for details.
 
 
Revisions
--------------------------------------------------------
 
   January 13, 2002
 
            Added a brief discussion of the DAF run-time binary file format
            translation capability now present in the SPICE Toolkit.
 
   July 12, 1994
 
            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.
 
 
Intended Audience
--------------------------------------------------------
 
   This document is intended for users that require detailed knowledge of
   DAF-based file formats, such as the SP- and C-kernel formats already
   mentioned. It is also intended for users of the SPICELIB library who
   wish to create their own DAF-based file formats.
 
   Most users of DAF-based formats will not generally need to understand
   the material presented in this document. For example, users of NAIF SP-
   and C-kernel files 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.
 
 
Related Documents
--------------------------------------------------------
 
   The following NAIF documents contain material that is 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 SP-kernel (SPK) file 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) file containing spacecraft or
            instrument orientation (pointing).
 
       3.   COMMNT User's Guide (COMMNT.UG)
 
            This document describes how labels, descriptive text and other
            comments may be added to or removed from a DAF-based SPK or CK
            file.
 
 
DAF Run-Time Binary File Format Translation
--------------------------------------------------------
 
   Starting with the N0052 release of the SPICE Toolkit (January, 2002)
   certain supported platforms are able to read DAF-based binary files
   (SPK, CK and binary PCK) that were written using a different, or
   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, for details.
 
 
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 Fortran-77 subroutines, part
   of the NAIF Toolkit software library, SPICELIB.
 
   DAF is called an architecture instead of a format because it includes an
   extensible family of file formats, each of which is characterized by a
   pair of parameters. A file that conforms to any one of these formats is
   called an `array file'.
 
   An array file 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 subroutines in SPICELIB support the following operations:
 
       1.   Create, open, or close an array file.
 
       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) array file 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 an array file in SPICE transfer format into an
            equivalent binary file.
 
   The last two functions make array files portable to any environment that
   supports ANSI Standard Fortran-77.
 
 
DAF-based Formats
--------------------------------------------------------
 
   The DAF architecture has been designed with the intention that 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 an array file is created. Any
   two array files 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 an array file 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 an array file is 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.)
 
   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.
 
 
Array Addresses
--------------------------------------------------------
 
   The location of each array in an array file 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 array file is actually a standard Fortran-77 direct access
   file, with a particular record length. (Every array file has the same
   record length.) Each record is capable of storing up to 128 double
   precision numbers.
 
   It is convenient, however, to think of an array file 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 an array file 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.
 
 
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.
 
 
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 array file at a time for write access. When
   a program attempts to open a file for write access, an error is
   signalled if another file is already open for write access, or if the
   file is already open for read access. An error is also signalled if a
   program attempts to open a file for read access if the file is already
   open for write access. (Errors are signalled through the standard
   SPICELIB error handling mechanism.)
 
 
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 array file. When a program opens an array
            file 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 SPICELIB 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.
 
 
DAF Family of Subroutines
===========================================================================
 
   SPICELIB contains a family of subroutines that can be used to create,
   populate, and manipulate array files. The name of each routine begins
   with the letters `DAF', followed by a two- or three-character mnemonic.
   For example, the routine that begins a forward search of an array file
   is named DAFBFS, pronounced `DAF-B-F-S'. A complete list of mnemonics,
   translations, and calling sequences can be found at the end of this
   document.
 
   Each subroutine is prefaced by a complete SPICELIB 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.
 
   In this document, whenever a subroutine appears in an example, the
   translation of the mnemonic part of its name will appear to the right of
   the reference, in braces. For example,
 
      CALL DAFBFS ( HANDLE )                 { Begin forward search }
 
   Examples will make use of the structured DO ... END DO and DO WHILE ...
   END DO statements supported by the VAX/VMS Fortran compiler. These
   statements are easily converted to the standard equivalents
 
              DO label var = e1, e2, e3
                 stmt
      label   CONTINUE
 
   and
 
      label   IF       ( expr )
             .THEN
                 stmt
                 GO TO label
              END IF
 
 
Opening and Closing Array Files
--------------------------------------------------------
 
   An existing array file 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.
 
      CALL DAFOPR ( FNAME, HANDLE )          { Open for read }
      CALL DAFOPW ( FNAME, HANDLE )          { Open for write }
 
   Once opened, an array file can be closed by supplying its handle to
   DAFCLS.
 
      CALL DAFCLS ( HANDLE )                 { Close }
 
 
Creating Array Files
--------------------------------------------------------
 
   A new array file 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  )
 
   The internal name of an array file is simply a string of up to 60
   characters, 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 an array file. 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 array file remains open for write access until
   explicitly closed.
 
 
Modifying Reserved Records
--------------------------------------------------------
 
   When a DAF is created, the number of reserved records must be specified
   in the call to DAFONW. Because it is not always possible to know at the
   time the file is created exactly how many reserved records are needed,
   the reserved record area may need to be modified later. The reserved
   record area can be modified in two ways: reserved records can be added
   or they can be removed. DAFARR adds RESV number of reserved records to
   the end of the reserved record area. DAFRRR removes RESV number of
   reserved records from the end of the reserved record area.
 
      CALL DAFARR ( HANDLE, RESV )            { Add reserved records }
      CALL DAFRRR ( HANDLE, RESV )            { Remove reserved records }
 
 
Adding Arrays
--------------------------------------------------------
 
   A new array can be added to an existing array file 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 }
 
   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.
 
      CALL DAFBNA ( HANDLE, SUM, NAME )      { Begin new array }
 
   The elements of the array are added by DAFADA. The elements may be
   supplied in one shot,
 
      CALL DAFADA ( DATA, N )                { Add data to array }
 
   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 }
 
   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
   start a new array in the same file, without first ending the current
   array.
 
 
Adding Arrays to Multiple Array Files
--------------------------------------------------------
 
   It is possible 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 }
 
   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 signalled if DAFCAD is used to
   select an array file 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 array files. 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 array files 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 array files 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 array file' and `current array' apply to both
   adding data to arrays and to searching array files. 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.
 
 
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 }
 
 
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.
 
   Subroutines DAFBFS and DAFFNA are used to search an array file 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:
 
      CALL DAFBFS ( HANDLE )                 { Begin forward search }
      CALL DAFFNA ( FOUND  )                 { Find next array }
 
      DO WHILE ( FOUND )
          ...
         CALL DAFFNA ( FOUND )               { Find next array }
      END DO
 
   Subroutines DAFBBS and DAFFPA are likewise used to search an array file
   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:
 
      CALL DAFBBS ( HANDLE )                 { Begin backward search }
      CALL DAFFPA ( FOUND  )                 { Find previous array }
 
      DO WHILE ( FOUND )
          ...
         CALL DAFFPA ( FOUND )               { Find previous array }
      END DO
 
   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:
 
      CALL DAFBBS ( HANDLE )                 { Begin backward search }
      CALL DAFFPA ( FOUND  )                 { Find previous array }
 
      DO WHILE ( FOUND )
         CALL DAFGS ( SUM  )                 { Get summary }
         CALL DAFGN ( NAME )                 { Get name }
          ...
         CALL DAFFNA ( FOUND )               { Find next array }
      END DO
 
   Once returned, a name can be examined directly. However, a summary must
   first be unpacked into its components by subroutine DAFUS:
 
      CALL DAFUS ( SUM, ND, NI, DC, IC )     { Unpack summary }
 
   The name and summary are used to determine whether the current array is
   of interest. For example, if the arithmetic mean of the elements in each
   array of an array file is stored in the second double precision
   component of the summary, then the following code fragment determines
   the initial and final addresses (IA and FA) of the array with the
   greatest average. (Assume function DPMIN returns the smallest double
   precision number supported in the host environment.)
 
      MAXAVG = DPMIN()
 
      CALL DAFBFS ( HANDLE )                 { Begin forward search }
      CALL DAFFNA ( FOUND  )                 { Find next array }
 
      DO WHILE ( FOUND )
         CALL DAFGS ( SUM )                  { Get summary }
         CALL DAFUS ( SUM, ND, NI, DC, IC )  { Unpack summary }
 
         IF ( DC(2) .GT. MAXAVG ) THEN
            MAXAVG  = DC(2)
            IA      = IC(NI-1)
            FA      = IC(NI  )
         END IF
 
         CALL DAFFNA ( FOUND )               { Find next array }
      END DO
 
   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.
 
 
Searching Multiple Array Files
--------------------------------------------------------
 
   Searching multiple array files 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 array file' 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 array file, DAFBFS or DAFBBS are
   called to start a search in a second array file, the second file becomes
   current: DAFFNA, DAFFPA, DAFGN, and DAFGS will all operate on the second
   file.
 
   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 }
 
   The routine DAFCS is used to continue a search in an array file 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 be signalled if DAFCS is used to continue a
   search in an array file in which no search has been started.
 
 
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 an array file 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
 
 
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.
 
      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 }
 
 
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 array files 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.)
 
 
Conversion and Transfer of DAF's
===========================================================================
 
   In order to be transferred to a new environment, a binary file is
   converted to an equivalent SPICE transfer file---a formatted, sequential
   file that contains only printable ASCII characters and blanks (ASCII
   32-126). In order to be used in the new environment, it is converted
   back to a binary file. This conversion process must occur because binary
   representations of numbers vary from machine to machine, the SPICE
   transfer representations do not.
 
   There are two routines for converting DAFs from binary to transfer and
   transfer to binary formats: DAFBT and DAFTB.
 
   DAFTB creates a new binary file. It then converts and writes the
   information from a previously opened SPICE transfer file to the binary
   file. Before returning to the calling program it closes the binary file.
   DAFTB leaves the SPICE transfer file open.
 
   DAFBT opens an existing binary file. It then converts and writes
   information from it to a previously opened SPICE transfer file. Before
   returning to the calling program it closes the binary file. DAFBT leaves
   the SPICE transfer file open.
 
   Note that the routines DAFBT and DAFTB make no use of the DAF reserved
   record area. They only convert the data portion of the DAF file.
 
   When converting a binary file for transfer (or archiving), it may be
   necessary to add additional information---catalog or history
   information, for example---to the resulting text file. The following
   code fragment creates a text file containing an ASCII array file
   preceded and followed by markers. The SPICELIB routine TXTOPN opens a
   new text file; TXTOPR opens an existing text file for read access.
 
      BEGMRK = '*** BEGIN ARRAY FILE ***'
      ENDMRK = '*** END ARRAY FILE ***'
 
      CALL TXTOPN ( FILENM, UNIT )
      WRITE (UNIT,*) BEGMRK
 
      CALL DAFBT ( BINARY, UNIT )           { Binary to transfer }
 
      WRITE ( UNIT,* ) ENDMRK
      CLOSE ( UNIT   )
 
   The following code fragment converts the resulting text file into a
   binary array file.
 
      CALL TXTOPR ( FILENM, UNIT )
      READ ( UNIT,FMT='(A)' ) BEGMRK
 
      CALL DAFTB ( UNIT, BINARY )          { Transfer to binary }
 
      READ  ( UNIT,FMT='(A)' ) ENDMRK
      CLOSE ( UNIT )
 
 
Structure
===========================================================================
 
   Every array file is a Fortran-77 direct access file, created by the
   following statement (or an equivalent statement producing the same
   results):
 
      OPEN ( UNIT   = unit,
             FILE   = file name,
             ACCESS = 'DIRECT',
             RECL   = record length,
             STATUS = 'NEW'           )
 
   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 or 1000 characters,
   whichever is larger. Some suitable values for several compilers are
   shown below.
 
      Compiler                          Record length
      --------------                   -------------
      HP Workstation
        /HP-UX
        /HP Fortran                         1024
 
      Macintosh
        /Language Systems Fortran           1024
 
      NeXT
        /Absoft Fortran                     1024
 
      PC
        /Lahey                              1024
 
      PC
        /Microsoft Fortran PowerStation     1024
 
      Silicon Graphics
        /IRIX
        /SGI Fortran                         256
 
      Sun
        /SunOS and Solaris
        /Sun FORTRAN                        1024
 
      VAX
        /OpenVMS
        /VAX Fortran                         256
 
      VAX
        /OSF/1
        /DEC Fortran                         256
 
      VAX
        /VMS
        /VAX Fortran                         256
 
 
Organization
--------------------------------------------------------
 
   An array file 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'. These records are
            provided so that the user can store information about the data
            within the DAF. Typical information might include the source of
            the data, or the names of programs used to process and
            interpret it.
 
       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. An
            array file contains one name record for each summary record.
 
       5.   An arbitrary number of `element records'. These contain
            elements of the arrays stored in the array file.
 
 
The File Record
 
   The file record is always the first physical record in an array file. It
   contains seven items.
 
       1.   An identification word (`DAF/xxxx'). Where 'xxxx' 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 an array file and not
            merely a direct access file with the same record length. When
            an array file is opened, an error is signalled if this keyword
            is not present.
 
       2.   The value of ND, the number of double precision components in
            each array summary.
 
       3.   The value of NI, the number of integer components in each array
            summary.
 
       4.   The internal name (60 characters) of the array file.
 
       5.   The record number of the initial summary record in the file.
 
       6.   The record number of the final summary record in the file.
 
       7.   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.
 
 
Reserved Records
 
   By definition, reserved records are invisible to DAF subroutines. The
   contents and formats of reserved records are left entirely to the user.
   The initial reserved record is located in the second record of the file;
   the final reserved record immediately precedes the initial summary
   record of the file.
 
   Reserved records may be used to store information about the data such as
   its source, names and sites of programs that processed it, names and
   sites of programs to interpret it, people to contact for support, its
   peculiarities or omissions, just to name a few.
 
 
Summary Records
 
   A summary record contains a maximum of 128 double precisions 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.)
 
   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
 
 
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.
 
   The values for ND and NI determine the maximum length for a name in the
   name record, NC:
 
                         (NI + 1)
      NC  =   8 * ( ND + -------- )     (Note that this is
                             2           integer division.)
 
   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.
 
 
Element Records
 
   Most of the records in any array file 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.
 
 
Designing a DAF
===========================================================================
 
   During the Voyager-2 encounter with Neptune, NAIF processed pictures
   using an image center finding technique in order to determine instrument
   pointing. For each body in each picture, a set of limb points---pixel
   and line pairs---was selected and an ellipse was fitted to the set,
   producing a center for the body.
 
   Suppose that the pixel and line pairs for the points are to be stored so
   that existing and future models can be used to interpret the data. While
   it's true that the pixel and line numbers are integers, they must be
   converted to double precision numbers for the ellipse fitting
   processing. As double precision numbers, they could be stored in a DAF.
 
   Data stored in a DAF is characterized by a set of double precision and
   integer values. In this case, each picture has several values associated
   with it that could be used to describe it: the picture number, the
   spacecraft identification code, the time at which the picture was taken,
   the identifier for the command load, the identifier for the camera, the
   identification code for the body whose center is described by the data.
   Examples of each of these items is given below:
 
 
      Picture number        :        9230.4
      Spacecraft event time :  -332927103.9324339
      Spacecraft ID         :         -32
      Load                  :         901
      Camera ID             :           1
      Body ID               :         899
 
 
   To specify the `format' of this DAF, the values of ND and NI must be
   determined. The number of double precision values used to describe the
   picture is two (picture number and spacecraft event time) so ND = 2. The
   number of integer values used to describe the picture is 4 (spacecraft
   ID, load, camera ID, and body ID). Because two of the integer components
   in the summary are used for storing locations of the arrays themselves,
   NI must always be two more than the number of integer values used to
   describe the data. In this example, NI = 4 + 2 = 6. Thus, the format of
   the DAF used to store the limb points is specified by ND = 2 and NI = 6.
 
   Having determined the values for ND and NI, the value of NC can be
   computed. NC is defined as :
 
                      (NI + 1)
      NC = 8 * ( ND + -------- )
                          2
 
   So, for this example:
 
                      (6 + 1)
      NC = 8 * ( 2 + -------- ) = 8 * ( 2 + 3 ) = 40
                         2
 
   In this example, each array name may contain a maximum of forty
   characters. The array names could describe the science activity of the
   scan platform. They would then give a clue as to what the picture might
   contain. For example, `Slew to center of Neptune' could be used to
   describe picture number 9230.4.
 
   After the format has been determined, the user needs to write software
   to transfer the limb point data to the DAF, and to read and interpret
   limb point data that has been stored in a DAF. Higher level DAF-based
   software, much like the SPK or CK software, can be written to achieve
   this functionality.
 
 
Creating an Array File
--------------------------------------------------------
 
   The following example illustrates the use of addresses and lists within
   an array file 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 and 1764,
   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.
 
 
Transfer Format for Porting
===========================================================================
 
   In order to transfer a DAF file from one computer platform to another,
   it should be converted to a SPICE transfer file. Previously, other
   SPICELIB routines such as DAFA2B, DAFB2A, DAFT2B, and DAFB2T were
   recommended for converting DAF files. These routines are now obsolete;
   however, they will remain in SPICELIB for backwards compatibility. Two
   routines replace them, DAFTB and DAFBT. Please use these routines in new
   software for converting DAF files. Older software does not need to
   changed to use the new routines. Software that calls the obsolete
   routines will continue to work properly, and the files they produce can
   be read using newer versions of the NAIF Toolkit.
 
 
Examples
===========================================================================
 
   The next several sections present example programs and subroutines to
   show how the DAF subroutines can be used to manipulate array files.
 
   All subroutines and functions used in the examples are from SPICELIB or
   they have been provided as examples themselves.
 
 
Example 1: Converting Between Transfer and Binary Format
--------------------------------------------------------
 
   This example is a complete program to convert a binary double precision
   array file (DAF) to an equivalent SPICE transfer file, suitable for
   porting to a different environment. The program queries the user for the
   names of the binary file to be converted and the transfer file to be
   created.
 
      PROGRAM B2T
 
      CHARACTER*(128)       BINARY
      CHARACTER*(128)       XFER
      INTEGER               XFLUN
 
      WRITE (*,*)         'Name of binary file?'
      READ  (*,FMT='(A)')  BINARY
 
      WRITE (*,*)         'Name of transfer file?'
      READ  (*,FMT='(A)')  XFER
 
      CALL TXTOPN ( XFER,   XFLUN )
      CALL DAFBT  ( BINARY, CFLUN )          { Binary to transfer }
 
      CLOSE ( XFLUN )
 
      END
 
   Now convert from SPICE transfer format back to binary:
 
      PROGRAM T2B
 
      CHARACTER*(128)       BINARY
      CHARACTER*(128)       TXFER
      INTEGER               TXTLUN
 
 
      WRITE (*,*)         'Name of text file?'
      READ  (*,FMT='(A)')  XFER
 
      WRITE (*,*)         'Name of binary file?'
      READ  (*,FMT='(A)')  BINARY
 
      CALL TXTOPR ( XFER,   XFLUN )
      CALL DAFTB  ( XFLUN, BINARY )          { Transfer to binary }
 
      CLOSE ( XFLUN )
 
      END
 
   The subroutines DAFBT and DAFTB can be embedded in programs with more
   sophisticated interfaces as well, such as X windows.
 
 
Example 2: Summarizing the Contents of an Array
--------------------------------------------------------
 
   The next example is a subroutine, SUMARR, that summarizes the contents
   of an array in a DAF. SUMARR assumes that a DAF file is open, a search
   (forward or backward) is in progress, and that an array has been found.
 
   The subroutine takes two character string arrays as inputs. Each
   character array contains labels describing what the double precision and
   integer components of the summary represent. A program calling SUMARR
   might print out each label followed by its corresponding value in the
   array summary.
 
   The function LASTNB returns the index of the last non-blank character in
   a string.
 
            SUBROUTINE SUMARR ( DNAMES, INAMES )
 
            CHARACTER*(*)       DNAMES ( * )
            CHARACTER*(*)       INAMES ( * )
 
      C
      C     SPICELIB functions
      C
            INTEGER             LASTNB
 
      C
      C     Local variables
      C
            CHARACTER*(80)      PNAME
 
            DOUBLE PRECISION    DC     ( 125 )
            DOUBLE PRECISION    SUM    ( 125 )
 
            INTEGER             HANDLE
            INTEGER             I
            INTEGER             IC     ( 250 )
            INTEGER             ND
            INTEGER             NI
            INTEGER             LONG
 
      C
      C     Look up the handle of the file, and the summary of the
      C     array most recently found.
      C
            CALL DAFGH  ( HANDLE         )
            CALL DAFHSF ( HANDLE, ND, NI )
 
      C
      C     Get, and unpack, the summary of the array. Note that SUM,
      C     DC, and IC are dimensioned large enough to hold the
      C     biggest possible summary.
      C
            CALL DAFGS  ( SUM )
            CALL DAFUS  ( SUM, ND, NI, DC, IC )
 
      C
      C     Find the length of the longest print name. All names will
      C     be transferred into a temporary string for printing.
      C     Shorter names will be followed by enough blanks to make
      C     the components line up.
      C
            LONG = 1
 
            DO I = 1, ND
               LONG = MAX ( LONG, LASTNB ( DNAMES(I) ) )
            END DO
 
            DO I = 1, NI
               LONG = MAX ( LONG, LASTNB ( INAMES(I) ) )
            END DO
 
      C
      C     Write the summary: an aligned list of components, each
      C     preceded by a descriptive name.
      C
            WRITE (*,*)
            WRITE (*,*) 'Summary'
            WRITE (*,*) '-------'
            WRITE (*,*)
 
            DO I = 1, ND
               PNAME = DNAMES(I)
               WRITE (*,*) PNAME(1:LONG), ' :', DC(I)
            END DO
 
            DO I = 1, NI
               PNAME = INAMES(I)
               WRITE (*,*) PNAME(1:LONG), ' :', IC(I)
            END DO
 
            RETURN
            END
 
   The following program uses SUMARR to summarize all of the arrays in a
   specific kind of array file. Each summary in the file contains four
   double precision components (minimum, maximum, average, standard
   deviation) and three integer components (sort flag, initial address,
   final address).
 
   Note that the program opens a DAF and begins a forward search. After an
   array is found by DAFFNA, it is summarized by SUMARR. This process of
   searching and summarizing continues until all of the arrays in the file
   have been summarized.
 
            PROGRAM SUMDAF
 
            INTEGER           ND
            PARAMETER       ( ND = 4 )
 
            INTEGER           NI
            PARAMETER       ( NI = 3 )
 
            CHARACTER*(40)    DNAMES  ( ND )
            CHARACTER*(40)    INAMES  ( NI )
            CHARACTER*(128)   FILE
 
            INTEGER           HANDLE
 
            LOGICAL           FOUND
 
            DATA              DNAMES     / 'Largest value',
           .                               'Smallest value',
           .                               'Average value',
           .                               'Standard deviation'   /
 
            DATA              INAMES     / 'Sorted (1=yes, 0=no)',
           .                               'Begins at address',
           .                               'Ends at address'      /
 
 
 
            WRITE (*,*)
            WRITE (*,*)         'Name of file?'
            READ  (*,FMT='(A)')  FILE
 
            CALL DAFOPR ( FILE, HANDLE )
 
            CALL DAFBFS ( HANDLE )
            CALL DAFFNA ( FOUND  )
 
            DO WHILE ( FOUND )
               CALL SUMARR ( DNAMES, INAMES )
               CALL DAFFNA ( FOUND )
            END DO
 
            END
 
   The summary of a typical array is shown below:
 
      Summary
      -------
 
      Largest value        : 221.42123212345
      Smallest value       : 17.332467369560
      Average value        : 148.37378239493
      Standard deviation   : 21.263546586965
      Sorted (1=yes, 0=no) : 0
      Begins at address    : 21463
      Ends at address      : 29271
 
 
Example 3: Copying Arrays from One File to Another
--------------------------------------------------------
 
   The next example is a subroutine to copy an entire array from one array
   file to another. It assumes that the array file that is to be updated
   already exists, a search (forward or backward) is in progress, and that
   an array has been found.
 
   It takes a single input: the name of the file to which the array is to
   be copied.
 
            SUBROUTINE COPYA ( FILE )
 
            CHARACTER*(*)      FILE
 
      C
      C     Local variables
      C
            CHARACTER*(1000)   NAME
 
            INTEGER            FA
            INTEGER            FIRST
            INTEGER            FROM
            INTEGER            HANDLE
            INTEGER            IA
            INTEGER            IC      ( 250 )
            INTEGER            LAST
            INTEGER            ND
            INTEGER            NI
            INTEGER            TO
 
            DOUBLE PRECISION   DATA    ( 100 )
            DOUBLE PRECISION   DC      ( 125 )
            DOUBLE PRECISION   SUM     ( 250 )
 
      C
      C     Get the handle of the source file, and the values
      C     of ND and NI for that file.
      C
            CALL DAFGH  ( FROM         )
            CALL DAFHSF ( FROM, ND, NI )
 
      C
      C     Open the target file for write access.
      C
            CALL DAFOPW ( FILE, TO )
 
      C
      C     Get the summary and name for the array to be copied.
      C     Start the new array.
      C
            CALL DAFGS ( SUM  )
            CALL DAFGN ( NAME )
 
            CALL DAFBNA ( TO, SUM, NAME )
 
      C
      C     Unpack the summary to get the initial and final addresses
      C     of the original array.
      C
            CALL DAFUS ( SUM, ND, NI, DC, IC )
            IA = IC(NI-1)
            FA = IC(NI  )
 
      C
      C     Copy the elements in groups of 100.
      C
            FIRST = IA
 
            DO WHILE ( FIRST .LE. FA )
 
               LAST  = MIN ( FA, FIRST + 100 - 1 )
               CALL DAFRDA ( FROM, FIRST, LAST, DATA )
               CALL DAFADA ( DATA, LAST - FIRST + 1 )
               FIRST = FIRST + 100
 
            END DO
 
      C
      C     Make the addition permanent, then close the target file.
      C
            CALL DAFENA
            CALL DAFCLS ( TO )
 
            RETURN
            END
 
 
Example 4: Copying Arrays to a New File in Sorted Order
--------------------------------------------------------
 
   The final example is a complete program to copy the arrays in one file
   to a second file, so that the arrays in the new file are sorted
   according to the value of the first double precision component of each
   summary.
 
   The program assumes that the file contains fewer than 1000 arrays.
 
   Subroutine ORDERD creates an order vector for a double precision array.
   Subroutine COPYA, defined in the previous example, is used to copy the
   arrays.
 
            PROGRAM DAFSRT
 
            CHARACTER*(128)       SOURCE
            CHARACTER*(128)       TARGET
            CHARACTER*(80)        ARCH
            CHARACTER*(80)        TYPE
 
            DOUBLE PRECISION      DC      (  125 )
            DOUBLE PRECISION      SUM     (  125 )
            DOUBLE PRECISION      VALUES  ( 1000 )
 
            INTEGER               HANDLE
            INTEGER               IC      (  250 )
            INTEGER               NA
            INTEGER               ND
            INTEGER               NI
            INTEGER               ORDER   ( 1000 )
            INTEGER               TO
            INTEGER               I
            INTEGER               J
            INTEGER               TARHAN
 
            LOGICAL               FOUND
 
 
      C
      C     Prompt for the names of the source and target files.
      C
            WRITE (*,*)
            WRITE (*,*)         'Name of source (unsorted) file?'
            READ  (*,FMT='(A)')  SOURCE
 
            WRITE (*,*)
            WRITE (*,*)         'Name of target (sorted) file?'
            READ  (*,FMT='(A)')  TARGET
 
      C
      C     Determine the file architecture and the type of data
      C     in the file.
      C
            CALL GETFAT ( SOURCE, ARCH,   TYPE     )
 
      C
      C     Open the source file, and look up the values of ND and NI
      C     for the file. That's needed for the call to DAFONW for
      C     opening the new DAF file later on.
      C
            CALL DAFOPR ( SOURCE, HANDLE           )
            CALL DAFHSF (         HANDLE, ND,   NI )
 
 
      C
      C     Collect the values of the first double precision
      C     component of each summary.
      C
            CALL DAFBFS ( HANDLE )
            CALL DAFFNA ( FOUND  )
 
            NA = 0
            DO WHILE ( FOUND )
               CALL DAFGS ( SUM )
               CALL DAFUS ( SUM, ND, NI, DC, IC )
 
               NA         = NA + 1
               VALUES(NA) = DC(1)
 
               CALL DAFFNA ( FOUND )
            END DO
 
      C
      C     Create an order vector for the values, such that ORDER(1)
      C     is the index of the array with the smallest value,
      C     ORDER(2) is the index of the array with the next smallest
      C     value, and so on.
      C
            CALL ORDERD ( VALUES, NA, ORDER )
 
      C
      C     Open the new file to initialize it, then close it
      C     immediately. We'll set the type of data in the file
      C     to be the same as the type of data in the original
      C     file. COPYA will reopen the file and copy an array
      C     to it.
      C
            CALL DAFONW ( TARGET, TYPE, ND, NI, 'Sorted file', 0,
           .              TARHAN                                  )
            CALL DAFCLS ( TARHAN )
 
      C
      C     Look up the arrays in the specified order (starting from
      C     the beginning of the file each time). Copy each one as
      C     it is found to the target file.
      C
            DO I = 1, NA
               CALL DAFBFS ( HANDLE )
 
               DO J = 1, ORDER(I)
                  CALL DAFFNA ( FOUND )
               END DO
 
               CALL COPYA ( TARHAN )
 
            END DO
 
            END
 
 
 
Summary of Mnemonics
--------------------------------------------------------
 
   SPICELIB contains a family of subroutines that can be used to create,
   populate, and manipulate double precision array files. The name of each
   routine begins with the letters `DAF', followed by a two- or
   three-character mnemonic. For example, the routine that begins a forward
   search of an array file is named DAFBFS, pronounced `DAF-B-F-S'. The
   following is a complete list of mnemonics and translations, in
   alphabetical order.
 
      ADA      Add data to array
      ARR      Add reserved records
      ARW      Address to record/word
      BBS      Begin backward search
      BFS      Begin forward search
      BNA      Begin new array
      CAD      Continue adding data
      CLS      Close
      CS       Continue search
      ENA      End new array
      FNH      File name to handle
      FNA      Find next array
      FPA      Find previous array
      GH       Get handle
      GN       Get name
      GS       Get summary
      HFN      Handle to file name
      HSF      Handle to summary format
      HLU      Handle to logical unit
      HOF      Handles of open files
      LUH      Logical unit to handle
      NRR      Number of reads, requests
      ONW      Open new
      OPR      Open for read
      OPW      Open for write
      PS       Pack summary
      RA       Re-order arrays
      RCR      Read character record
      RDA      Read data from address
      RDR      Read double precision record
      RFR      Read file record
      RN       Replace name
      RRR      Remove reserved records
      RS       Replace summary
      RWA      Record/word to address
      SIH      Signal invalid handles
      US       Unpack summary
      WCR      Write character record
      WDA      Write data to address
      WDR      Write double precision record
      WFR      Write file record
 
   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 (RCR, RDR, RFR, WCR, WDR, WFR) are low level
   routines, they are not usually called by a typical user, but instead by
   higher level DAF routines.
 
 
Summary of Calling Sequences
===========================================================================
 
   The calling sequences for the DAF subroutines are summarized below.
   Subroutines are grouped by function.
 
   Opening and closing files:
 
 
      ONW ( FNAME, FTYPE, ND, NI, IFNAME, RESV, HANDLE )
      OPR ( FNAME,                              HANDLE )
      OPW ( FNAME,                              HANDLE )
      CLS (                                     HANDLE )
 
   Modifying reserved records:
 
      ARR ( HANDLE, RESV )
      RRR ( HANDLE, RESV )
 
   Adding an array to a file:
 
      BNA ( HANDLE, SUM, NAME )
      ADA ( DATA,   N         )
      CAD ( HANDLE            )
      ENA
 
   Finding an array within a file:
 
      BFS ( HANDLE )
      FNA ( FOUND  )
 
      BBS ( HANDLE )
      FPA ( FOUND  )
 
      CS  ( HANDLE )
 
      GH ( HANDLE )
      GN ( NAME   )
      GS ( SUM    )
      RN ( NAME   )
      RS ( SUM    )
 
      US  ( SUM, ND, NI, DC, IC      )
      PS  (      ND, NI, DC, IC, SUM )
 
   Reading and writing arrays:
 
      RDA ( HANDLE, BEGIN, END, DATA )
      WDA ( HANDLE, BEGIN, END, DATA )
 
   Reordering arrays:
 
      RA ( HANDLE, IORDER, N )
 
   Converting array files:
 
      BT ( BINARY, TXTLUN )
      TB ( TXTLUN, BINARY )
 
   Reading, writing physical records:
 
      RFR ( HANDLE, ND, NI, IFNAME, FWARD, BWARD, FREE )
      WFR ( HANDLE, ND, NI, IFNAME, FWARD, BWARD, FREE )
 
      RCR ( HANDLE, RECNO, CREC )
      WCR ( HANDLE, RECNO, CREC )
 
      RDR ( HANDLE, RECNO, BEGIN, END, DATA, FOUND )
      WDR ( HANDLE, RECNO,             DREC        )
      NRR ( READS,  REQS                           )
 
   Internal conversions:
 
      HSF ( HANDLE, ND, NI )
 
      FNH ( FNAME,  HANDLE )
      HFN ( HANDLE, FNAME  )
      HLU ( HANDLE, UNIT   )
      LUH ( UNIT,   HANDLE )
 
      ARW ( ADDR, RECNO, WORDNO       )
      RWA (       RECNO, WORDNO, ADDR )
 
   Error handling utilities:
 
      HOF ( FHSET          )
      SIH ( HANDLE, ACCESS )
 
   Related routine--Determining file architecture and type:
 
      GETFAT ( FILE, ARCH, TYPE )
 
 
Obsolete Routines
===========================================================================
 
   The following is a list of routines and their replacements. NAIF's
   policy is to maintain the old routines to assure that existing software
   continues to function. Bugs will be fixed; however, no new functionality
   will be added to them. The replacement routines should be used in any
   new software that is being developed. Existing software does not need to
   be updated.
 
   As always, for more information about a given routine, see its header
   documentation.
 
      Routine   Replacement   Description
      --------  ------------  ----------------------------------
      DAFOPN    DAFONW        Open new DAF file
      DAFA2B    DAFTB         Convert transfer to binary format
      DAFB2A    DAFBT         Convert binary to transfer format
      DAFB2T    DAFBT         Convert binary to transfer format
      DAFT2B    DAFTB         Convert transfer to binary format
 
