First consider processing the data arrays of two input NDFs. Under what circumstances should checks for bad pixels be made?
The capabilities of real applications in this area usually fall into one of the following categories:
It is expected that the majority of applications will fall into categories 1 and 2, since only a few general-purpose software items are likely to obtain worthwhile benefit from attempting to optimise their behaviour when bad pixels are known to be absent (category 3). Nevertheless, it is instructive to consider this last and most complicated category first.
As already noted, there are four possible combinations of bad-pixel flags if we consider the data components of a pair of NDFs (there would be considerably more if we wanted to include the variance components as well). For all practical purposes, however, the number of combinations can be reduced to two by merging the bad-pixel flags of the separate array components using a logical ``OR'', for instance:
LOGICAL BAD1, BAD2, BAD
...
CALL NDF_BAD( INDF1, 'Data', .FALSE., BAD1, STATUS )
CALL NDF_BAD( INDF2, 'Data', .FALSE., BAD2, STATUS )
BAD = BAD1 .OR. BAD2
...
The resulting value of BAD could then be used to determine whether checks for bad-pixel values are necessary. For instance, if the two data arrays were to be added, the main processing algorithm might look like this:
SUBROUTINE ADDIT( BAD, EL, A, B, C, STATUS )
INCLUDE 'SAE_PAR'
INCLUDE 'PRM_PAR'
LOGICAL BAD
INTEGER EL, STATUS, I
REAL A( EL ), B( EL ), C( EL )
IF ( STATUS .NE. SAI__OK ) RETURN
* No bad-pixel checks needed, so add the arrays.
IF ( .NOT. BAD ) THEN
DO 1 I = 1, EL
C( I ) = A( I ) + B( I )
1 CONTINUE
* Bad pixel checks needed, so check and assign a bad result if necessary.
ELSE
DO 2 I = 1, EL
IF ( A( I ) .EQ. VAL__BADR .OR. B( I ) .EQ. VAL__BADR ) THEN
C( I ) = VAL__BADR
* Otherwise add the array elements normally.
ELSE
C( I ) = A( I ) + B( I )
END IF
2 CONTINUE
END IF
END
Although this is the most sophisticated response to the presence of bad pixels which we will consider, two compromises have nevertheless still been made here. First, the main processing algorithm will sometimes run slightly more slowly than is absolutely necessary, because taking the logical ``OR'' means that checks will occasionally be made for bad pixels in arrays which do not contain any. Secondly, as a result of this, some ``good'' pixels may accidentally be identified as bad and a small fraction of valid pixels might therefore be lost. In practice, both of these penalties are usually acceptably small, given the alternative (of writing many versions of the main processing algorithm to cater for every combination of bad-pixel flags).
So what should happen if the main processing algorithm is very simple and
cannot handle any bad pixels at all (category 1 above)?
In this case, it is not possible to compromise, because attempting to ignore
the situation and process an array containing bad pixels without
checking for them will give a completely wrong result (as well as causing
severe numerical problems which will probably cause the application to
crash).
In this situation, the limitations of the application are paramount, and the
correct response is to report an error and abort (see
§).
A user would then have the option of running a separate application to
``repair'' the data by replacing bad pixels with an acceptable
alternative.
The need to handle bad-pixel flags in any of the ways described above is very common, so the prototype merging and matching routine NDF_MBAD is provided to simplify the process. This routine merges the bad-pixel flags of a pair of NDFs and matches them to the capabilities of an application. Its first (BADOK) argument is supplied with a logical value indicating whether the calling application can handle bad pixels or not, for instance:
LOGICAL BADOK, CHECK, BAD
...
CALL NDF_MBAD( BADOK, INDF1, INDF2, 'Data', CHECK, BAD, STATUS )
If the BADOK argument is set to .TRUE., then NDF_MBAD simply returns
the logical ``OR'' of the bad-pixel flags for each of the two NDFs via
its BAD argument.
In this case it behaves in most respects exactly like its simpler relative
NDF_BAD (see §).
However, if BADOK is set to .FALSE., but the returned BAD value would
nevertheless be .TRUE. (indicating that bad pixels may be present in
one of the NDFs), then an error results.
NDF_MBAD then makes an appropriate error report, explaining that the
application cannot handle the bad pixels, and returns with its STATUS
argument set to NDF__BADNS (bad values not supported), as defined in the
include file NDF_ERR.
In the normal course of events, the application would then abort and this
message would be delivered to the user.
A call to NDF_MBAD therefore allows an application to declare whether it can handle bad pixels, and then determines whether checks for bad pixels should actually be made. At the same time, it will handle any problems which may arise.
If more than two NDF's are involved, then the routine NDF_MBADN may be used instead of NDF_MBAD. This routine exists for merging the bad-pixel flag values of an arbitrary number of NDFs, whose identifiers are supplied in an integer array. For instance:
INTEGER N, NDFS( N )
...
CALL NDF_MBADN( .FALSE., N, NDFS, 'Data', .TRUE., BAD, STATUS )
could be used by an application which was incapable of handling bad pixels in order to check for their existence in a whole sequence of NDFs at once.
Finally, if only a single NDF is being used, then there is a choice. The routine NDF_MBADN may be called with N set to 1, but NDF_MBAD may also be used by passing the same identifier value twice, as follows:
CALL NDF_MBAD( BADOK, INDF1, INDF1, COMP, CHECK, BAD, STATUS )
NDF_MBAD is designed to expect this kind of usage, and will detect it and behave appropriately without any loss of efficiency. All the other equivalent matching and merging routines described in subsequent sections also have this capability.