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.
July 12, 1994
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 and CK Required Reading files.
The following NAIF documents contain material that is closely related to the
subject of this document.
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:
The DAF architevture 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 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 <= 250Each 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.
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.
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.
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.)
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.
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 CONTINUEand
label IF ( expr ) .THEN stmt GO TO label END IF
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 }
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.
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 }
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 DOOnce 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.
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 DOEnd 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 DAFENAThe 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.
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 }
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 DOSubroutines 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 DOOnce 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 DOOnce 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 DORecall 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 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.
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
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 }
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 (%) = ', PERCNTIdeally, 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.)
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 )
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
An array file contains five types of physical records:
The file record is always the first physical record in an array file. It
contains seven items.
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.
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:
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 | NSUMIf 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
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.
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.
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 : 899To 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 + -------- ) 2So, for this example:
(6 + 1) NC = 8 * ( 2 + -------- ) = 8 * ( 2 + 3 ) = 40 2In 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.
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:
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 = 27Each array summary requires 39 double precision words of storage:
(NI + 1) ND + -------- = 25 + 14 = 39 2Therefore, 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 UnusedThe 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 2Each 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 UnusedAssume 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 = 12DAFONW 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 = 1665DAFONW 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 A1Assume 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 A2To 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 A3Note 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.
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.
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.
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 ) ENDNow 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 ) ENDThe subroutines DAFBT and DAFTB can be embedded in programs with more sophisticated interfaces as well, such as X windows.
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 ENDThe 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 ENDThe 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
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
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
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 recordMany 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.
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 ) ENAFinding 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 )
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