4 A simple program

The program discussed in this section reports the dimensions of the main data array of an input NDF. The code for REPDIM.FOR is reproduced below and can be copied from the directory ADAM_EXAMPLES.

        SUBROUTINE REPDIM (STATUS)
        IMPLICIT NONE
        INCLUDE ’SAE_PAR’
        INTEGER DIM(10), I, NDF1, NDIM, STATUS
  
  *   Check inherited global status.
        IF (STATUS.NE.SAI__OK) RETURN
  
  *   Begin an NDF context.
        CALL NDF_BEGIN
  
  *   Get the name of the input NDF file and associate an NDF identifier with it.
        CALL NDF_ASSOC (’INPUT’, ’READ’, NDF1, STATUS)
  
  *   Enquire the dimension sizes of the NDF and write them out.
        CALL NDF_DIM (NDF1, 10, DIM, NDIM, STATUS)
        IF (STATUS.EQ.SAI__OK) THEN
           WRITE(*,*) NDIM, (DIM(I), I=1,NDIM)
        ENDIF
  
  *   End the NDF context.
        CALL NDF_END (STATUS)
        END

The interface file REPDIM.IFL, associated with the above routine is as follows:

  interface REPDIM
    parameter      INPUT
       prompt      ’Input NDF structure’
    endparameter
  endinterface

The application code explained.

But how does it work? To examine the code in detail:

        SUBROUTINE REPDIM (STATUS)
        IMPLICIT NONE
        INCLUDE ’SAE_PAR’
        INTEGER DIM(10), I, NDF1, NDIM, STATUS

The main subroutine is declared with the single STATUS argument as with all ADAM applications. The IMPLICIT NONE statement forces the explicit declaration of the type of all variables used within the program. The use of this extension is generally recommended for Starlink programming. The next statement includes the file with logical name SAE_PAR which contains a set of symbolic constants used in ADAM. The only such constant used in this example is SAI__OK which corresponds to the ‘OK’ value of STATUS 4. The fourth statement above simply declares the variables used.

  *   Check inherited global status.
        IF (STATUS.NE.SAI__OK) RETURN

Most subroutines used in ADAM include the variable STATUS as the last argument. (In the case of ‘main’ subroutines like REPDIM.FOR, STATUS is the only argument.) The STATUS value is checked on entering a routine, and if it does not correspond to the ‘OK’ value (SAI__OK), control simply returns to the calling routine. This method of inherited status checking greatly simplifies the coding of applications as it is unnecessary to keep checking STATUS before proceeding with the next stage of the program – if STATUS has been set to a non-ok value, then a succession of calls to a series of routines will simply ‘fall through’ with each subroutine returning control as soon as it tests the STATUS value.

  *   Begin an NDF context.
        CALL NDF_BEGIN

This statement begins an NDF context which ends with the NDF_END at the end. The significance of this context is that any clearing up made necessary by NDF routines called during the context will be done automatically by the NDF_END. The programmer familiar with HDS will realise that this means there is no need to worry about explicitly annulling identifiers or unmapping arrays etc.

  *   Get the name of the input NDF file and associate an NDF identifier with it.
        CALL NDF_ASSOC (’INPUT’, ’READ’, NDF1, STATUS)

This is the statement which uses the interface file. The first argument of the NDF_ASSOC call is an ADAM parameter – in this case called ’INPUT’. Parameters are used to refer to values which are input by the user of an ADAM program. The parameter ’INPUT’ is defined in the interface file, and referring to it causes the prompt specified in REPDIM.IFL to be issued. The value supplied by the user is returned to the program. The file named is opened, in this case with ’READ’ access as specified, and an NDF identifier (NDF1) used to refer to the input NDF is returned.

  *   Enquire the dimension sizes of the NDF and write them out.
        CALL NDF_DIM (NDF1, 10, DIM, NDIM, STATUS)
        IF (STATUS.EQ.SAI__OK) THEN
           WRITE(*,*) NDIM, (DIM(I), I=1,NDIM)
        ENDIF

These lines do most of the work of the program. The NDF_DIM call will return the dimensions of the main data array for the NDF associated with the NDF1 identifier. Ten is an arbitrary choice for the maximum number of dimensions which the program expects. DIM and NDIM accommodate the dimensions and the total number of dimensions respectively. The WRITE statement used to report the answers would not be found in a proper ADAM program (see overleaf). Note that it is necessary to check STATUS before executing the WRITE statement, as it would not be appropriate to output the answers if STATUS were not OK. (Of course, if the output were done using a routine which used inherited status checking, the check would be unnecessary.)

  *   End the NDF context.
        CALL NDF_END (STATUS)
        END

The NDF_END matches the NDF_BEGIN, and as described above, this routine does any tidying up incurred by calls made since the last NDF_BEGIN.

The program can be compiled and linked and tested with an NDF as shown below:

  $ FORTRAN REPDIM
  $ ALINK REPDIM
  $ RUN REPDIM
  INPUT - Input NDF structure > SPECTRUM
           1         852

4If you $ TYPE SAE_PAR you will probably see that the value of SAI__OK is zero, but different implementations of ADAM may redefine the value of this and other symbolic constants, so it is important that they are used in preference to the numbers they represent in programs.