10 Creating NDFs from scratch – a format conversion routine

This section presents a format conversion routine – an NDF is created from data in a text file. Only portions of the program are reproduced below; the full source code and interface file are contained in ADAM_EXAMPLES:OUTNDF.FOR and OUTNDF.IFL. (The part of the program which reads the input text file is very similar to the code used to illustrate the use of the FIO package in Section 9.)

A new NDF is created with the call:

        CALL NDF_CREAT (PARAM, TYPE, NDIM, LBND, UBND, NDF, STATUS)

where, PARAM is the ADAM parameter used to get the name of the NDF; TYPE is the data type required for the main data array, NDIM is the number of dimensions for the main data array, LBND and UBND are integer arrays containing the lower and upper pixel bounds respectively as described below, NDF contains the NDF identifier allocated, and STATUS is the global status.

The arrays LBND and UBND require a little explanation. Just like a Fortran array, an NDF may have dimensions in which the array index begins with a number other than one. The shape of an NDF is completely specified by the number of dimensions and the lower and upper pixel bound of each dimension. For example (2:6, 0:100) describes a 2-D array with pixel indices ranging from 2 to 6 in the first dimension and 0 to 100 in the second. An NDF with this shape could be created by calling NDF_CREAT with NDIM = 2, LBND(1) = 2, LBND(2) = 0, UBND(1) = 6 and UBND(2) = 100. In the example below, the lower pixel index bound is simply set to one.

The program OUTNDF reads a text file with the format shown below:

  IUE spectrum of Saturn
  534
     1191.200      1.6757190E-13
     1198.279      1.2435831E-13
     ...            ...

That is, a title on the first line, the number of data elements on the second, followed by successive pairs of axis and data values.

In OUTNDF.FOR the title of the NDF and the number of data elements are read into TITLE and NELM respectively. The program only deals with 1-d data so the number of dimensions, NDIM, is set to one. The lower bound of the main data array is set to one, and the upper bound is set to NELM. An NDF is then created with the call to NDF_CREAT as shown below.

The title read from the text file is used to set the NDF title. Note that the main data and axis arrays are not read in the main subroutine OUTNDF – this is to avoid the necessity of declaring arrays to accommodate them. Instead the arrays are mapped for ’WRITE’ in the output NDF and the dynamically allocated space is used in the subroutine GTDATA to read in the arrays from the text file.

The code which creates the output NDF is reproduced below:

  *  Use FIO to open the input text file and get the logical unit number.
  *  Read TITLE and NELM, and check NELM is greater than zero.
  *   ...
  
  *   Begin an NDF context.
        CALL NDF_BEGIN
  
  *  The lower pixel bound is set to unity, the upper to the number of
  *  elements. The number of dimensions is set to one.
        LBND(1) = 1
        UBND(1) = NELM
        NDIM = 1
  
  *   Create a new NDF file and associate an NDF identifier with it.
  *   A data array of the correct size is specified via NDIM
  *   and the LBND, UBND arrays.
        CALL NDF_CREAT (’OUTPUT’, ’_REAL’, NDIM, LBND, UBND, NDF, STATUS)
  
  *   Put the TITLE read from the input file into the NDF title.
        CALL NDF_CPUT (TITLE, NDF, ’TITLE’, STATUS)
  
  *   Map the NDF main data array for WRITE.
        CALL NDF_MAP (NDF, ’DATA’, ’_REAL’, ’WRITE’, DATPTR, NELM, STATUS)
  
  *   Map the NDF AXIS(1) array for WRITE.
        CALL NDF_AMAP (NDF, ’CENTRE’, 1, ’_REAL’, ’WRITE’, AXPTR, NELM,
       :               STATUS)
  
  *   Call a subroutine to read the input data into the mapped data arrays.
        CALL GTDATA (UNIT, NELM, %VAL(AXPTR), %VAL(DATPTR), STATUS)
  
  *   End the NDF context.
        CALL NDF_END (STATUS)
  
  999   CONTINUE
  
  *   Report any I/O errors, shut down FIO and end.
  *    ...

And the subroutine which reads the data…

  *   Subroutine to read main data and axis arrays.
        SUBROUTINE GTDATA (UNIT, NELM, WAVE, FLUX, STATUS)
        IMPLICIT NONE
        INCLUDE ’SAE_PAR’
        INTEGER NELM, I, IOSTAT, STATUS, UNIT
        REAL WAVE(NELM), FLUX(NELM)
  
        IF (STATUS.NE.SAI__OK) RETURN
  
  *   Read the data arrays.
        READ (UNIT, *, IOSTAT=IOSTAT) (WAVE(I), FLUX(I), I=1,NELM)
  
  *   Report any I/O error.
  *    ...
        END

The program OUTNDF can be tested with the data file SATURN.DAT in ADAM_EXAMPLES and can easily be adapted to deal with other data formats as required.