### 7 ARRAY COMPONENT TYPES

This section introduces the concept of the numerical type, or precision, of an NDF’s array components and shows how the value of this attribute may be obtained and modified.

#### 7.1 Numeric Types

Each of an NDF’s array components (i.e. its data, quality and variance) has an attribute termed its numeric type, which refers to the numerical precision used to store its pixel values. The NDF_ system allows array components to be stored using any of seven numeric types which correspond with the seven primitive numeric types provided by the underlying data system HDS. It also uses the same character strings as HDS to refer to these types, as follows:

 Character String Numeric Type Fortran Type ’_DOUBLE’ Double-precision DOUBLE PRECISION ’_REAL’ Single-precision REAL ’_INTEGER’ Integer INTEGER ’_WORD’ Word INTEGER * 2 ’_UWORD’ Unsigned word INTEGER * 2 ’_BYTE’ Byte BYTE ’_UBYTE’ Unsigned byte BYTE

The HDS documentation (SUN/92) should be consulted for details of the range and precision of each of these numeric types, which may depend on the computer hardware in use. Note that character and logical types are not provided.

The numeric type of an array component is defined regardless of the component’s state. The numeric type of the data component is specified when the NDF is created and the numeric type of its variance component will normally default to the same value, although both of these types may subsequently be altered (see §7.4). In contrast, the numeric type of the quality component is always ‘_UBYTE’ and cannot be changed.

The numeric type of any NDF array component can be determined using the routine NDF_TYPE. For instance:

INCLUDE ’NDF_PAR’
CHARACTER * ( NDF__SZTYP ) TYPE

...

CALL NDF_TYPE( INDF, ’Data’, TYPE, STATUS )

will return the numeric type of an NDF’s data component as an upper case character string via the TYPE argument. Note how the symbolic constant NDF__SZTYP (defined in the include file NDF_PAR) should be used to declare the size of the character variable which is to receive the returned numeric type string.

The NDF_TYPE routine will also accept a list of array components. In this case, it will determine the numeric type of each component in the list and return the lowest-precision numeric type to which all these components can be converted without unnecessary loss of information. For instance, if values from the data and variance components of an NDF were to be combined, then a suitable numeric type for performing the processing could be obtained as follows:

CALL NDF_TYPE( INDF, ’Data,Variance’, TYPE, STATUS )

If the data component held ‘_WORD’ values and the variance component held ‘_REAL’ values, then a value of ‘_REAL’ would be returned indicating that both components could be accessed for processing using single-precision floating-point arithmetic without losing information. The question of type conversion during array component access is discussed later (see §8.7).

#### 7.2 Complex Values

In addition to its numeric type, each NDF array component also has a logical complex value flag associated with it, which indicates whether it holds complex values. If so, then each pixel of that array is a complex number, with separate real and imaginary parts. Both parts share the same numeric type.

The complex value flag for an NDF’s data component is established when the NDF is created and the variance component will normally adopt the same value by default, although both may subsequently be altered (see §7.4). In contrast, the quality component can never hold complex values, so its complex value flag remains set to .FALSE. and cannot be changed.

It is possible to determine whether an array component holds complex values by using the routine NDF_CMPLX. For instance:

CALL NDF_CMPLX( INDF, ’Variance’, CMPLX, STATUS )

would return a logical .TRUE. result via the CMPLX argument if the NDF’s variance component held complex values. As with NDF_TYPE, a list of components may also be specified, in which case the logical “OR” of the results for each component will be returned. Thus:

CALL NDF_CMPLX( INDF, ’Data,Variance’, CMPLX, STATUS )

will return a .TRUE. result if either the data or variance component holds complex values.

#### 7.3 Full Type Specifications

The combination of the seven numeric types and a complex value flag gives rise to a further seven complex types, which are conveniently expressed by prefixing the character string ‘COMPLEX’ to the numeric type, as follows:

 ’COMPLEX_DOUBLE’ ’COMPLEX_REAL’ ’COMPLEX_INTEGER’ ’COMPLEX_WORD’ ’COMPLEX_UWORD’ ’COMPLEX_BYTE’ ’COMPLEX_UBYTE’

Strings such as these, which represent both the numeric type and the complex value flag, are termed the full type specification of an NDF’s array component. Note that a string such as ‘_REAL’ can also be considered as a special case of a full type specification in which the “complex” field is blank.

The full type of an array component can be derived if necessary, but the routine NDF_FTYPE will return it directly. For instance:

INCLUDE ’NDF_PAR’
CHARACTER * ( NDF__SZFTP ) FTYPE

...

CALL NDF_FTYPE( INDF, ’Data’, FTYPE, STATUS )

will return the full type of an NDF’s data component as an upper-case character string via the FTYPE argument. Note how the symbolic constant NDF__SZFTP (defined in the include file NDF_PAR) should be used to declare the size of the character variable which is to receive the returned full type specification.

As might be expected, NDF_FTYPE will also accept a list of array components, returning a full type specification which combines the numeric types and the complex value flags of the individual components in the same way as the routines NDF_TYPE and NDF_CMPLX would have done individually. Thus:

CALL NDF_FTYPE( INDF, ’Data,Variance’, FTYPE, STATUS )

will combine the full type specifications of both the data and variance components of an NDF, and return the resultant string.

#### 7.4 Setting Component Types

So long as the necessary access is available (see §23.1), the full type of an NDF’s data and variance components may be explicitly set when required, thereby altering the precision with which their values are stored. This may be done using the routine NDF_STYPE. For instance:

CALL NDF_STYPE( ’_REAL’, INDF, ’Data’, STATUS )

would change the type of an NDF’s data component to ‘_REAL’. This process will retain pixel values which may already be stored in the affected component; i.e. if these values are defined, then they will be converted to the new type and will not be lost. Of course, this may not always be needed, so it is possible to arrange for existing values to be disposed of, if necessary, in order to avoid the cost of converting the pixel values. This is done by calling NDF_RESET to reset the component’s values to an undefined state prior to changing its type, thus:

CALL NDF_RESET( INDF, ’Data’, STATUS )
CALL NDF_STYPE( ’_REAL’, INDF, ’Data’, STATUS )

No attempt will then be made by NDF_STYPE to convert individual pixel values, so changing the type of an array component becomes a relatively inexpensive operation. Note that no harm is done by calling NDF_RESET in this way even if the component’s state is already undefined.

NDF_STYPE will also accept a list of components and will set them all to the same type. For instance:

CALL NDF_STYPE( ’COMPLEX_DOUBLE’, INDF, ’Data,Variance’, STATUS )

would set both the data and variance components of an NDF to be of type ‘COMPLEX_DOUBLE’ (i.e. to have real and imaginary parts, both stored as double-precision numbers). Changes may be made freely between non-complex and complex types, and conversion of pixel values will be performed if these values are defined; either an imaginary part filled with zeros will be supplied, or the imaginary part will be discarded, as appropriate.