next up previous 204
Next: Examples of Possible User Responses
Up: An Example of a Simple GRP Application
Previous: An Example of a Simple GRP Application

Example Code

Here is a simple example of the use of GRP which illustrates the ideas of indirection and modification. In this example, each stored string corresponds to the name of a file but obviously an application could apply other interpretations. The user is prompted for a set of input file names and then prompted again for a set of output file names. Each input file is processed in some way (by routine PROC) to produce the corresponding output file. The source code that follows is not intended to provide all the information necessary to write GRP applications, but simply to give a feeling for the way GRP works:
      SUBROUTINE GRP_TEST( STATUS )                             [1]
      IMPLICIT NONE

*  Include definitions of global constants.
      INCLUDE 'SAE_PAR'                                         [2]
      INCLUDE 'GRP_PAR'                                         [3]

*  Declare local variables.
      INTEGER STATUS, IGRP1, IGRP2, SIZE1, SIZE2, ADDED, I
      CHARACTER*(GRP__SZNAM) INFIL, OUTFIL
      LOGICAL FLAG

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

*  Create a new (empty) group to contain the names of the
*  input files.
      CALL GRP_NEW( 'Input files', IGRP1, STATUS )              [5]

*  Prompt the user for a group of input file names and place
*  them in the group just created.
      CALL GRP_GROUP( 'IN_FILES', GRP__NOID, IGRP1, SIZE1,      [6]
     :                ADDED, FLAG, STATUS )

*  Create a second group to hold output file names.
      CALL GRP_NEW( 'Output files', IGRP2, STATUS )             [7]

*  Prompt the user for a group of output file names, giving
*  the chance to specify them by modification of the input
*  file names. Place the output file names in the new group
*  just created.
      CALL GRP_GROUP( 'OUT_FILES', IGRP1, IGRP2, SIZE2,         [8]
     :                ADDED, FLAG, STATUS )

*  Report an error and abort if the number of output files
*  does not equal the number of input files.
      IF( SIZE2 .NE. SIZE1 .AND. STATUS .EQ. SAI__OK ) THEN     [9]
         STATUS = SAI__ERROR
         CALL ERR_REP( 'GRP_TEST_ERR1',
     :           'Incorrect number of output files specified',
     :           STATUS )
         GO TO 999
      END IF

*  Loop round each input file.
      DO I = 1, SIZE1                                           [10]

*  Retrieve the input file name with index given by I.
         CALL GRP_GET( IGRP1, I, 1, INFIL, STATUS )             [11]

*  Retrieve the output file name with index given by I.
         CALL GRP_GET( IGRP2, I, 1, OUTFIL, STATUS )

*  Process the data.
         CALL PROC( INFIL, OUTFIL, STATUS )                     [12]

*  Do the next input file.
      END DO

*  Delete the groups created by this application.
 999  CONTINUE
      CALL GRP_DELET( IGRP1, STATUS )                           [13]
      CALL GRP_DELET( IGRP2, STATUS )

      END

Programming notes:

  1. The example is actually an ADAM A-task, and so consists of a subroutine with a single argument giving the inherited status value. See SUN/101 for further details about writing ADAM A-tasks. A ``stand-alone'' version of the GRP package is available which can be used with non-ADAM applications.

  2. The first INCLUDE statement is used to define standard ``symbolic constants'', such as the values SAI__OK and SAI__ERROR which are used in this routine. Starlink software makes widespread use of such constants, which should always be defined in this way rather than by using actual numerical values. The file SAE_PAR is almost always needed, and should be included as standard in every application.

  3. The second INCLUDE statement performs a similar function to the first, but defines symbolic constants which are specific to the GRP package. Such constants are recognizable by the fact that they start with the five characters ``GRP__'' (such as GRP__NOID and GRP__SZNAM used in the above example). Note the double underscore ``__'' which distinguishes them from subroutine names.

  4. The value of the STATUS argument is checked. This is because the application uses the Starlink error handling strategy (see SUN/104), which requires that a subroutine should do nothing unless its STATUS argument is set to the value SAI__OK on entry. Here, we simply return without action if STATUS has the wrong value.

  5. An identifier for a new group is now obtained. The variable IGRP1 is returned holding an integer value which the GRP package uses to recognise the group just created. Initially, there are no names stored in the group. A string is stored which should be used to give a description of the type of objects stored within the group (in this case the string ``Input files'' is used).

  6. The user is now prompted for a value for the parameter IN_FILES, and replies with a string, which GRP splits up into separate elements, each element being either a literal file name or the name of a text file containing other file names. As there are no other groups defined at this point, it is not possible to specify the files names using ``modification'' (as described in item [*] in section [*]). For this reason, the second argument (which would normally specify the group to use as the basis for modification) is given the value GRP__NOID. This is a special identifier value used to indicate a ``null'' group. The names supplied by the user are stored in the group created by the previous call to GRP_NEW, and the number of names is returned in argument SIZE1. Note, no permanent association exists between the group identified by IGRP1 and the parameter IN_FILES (which is one reason why GRP_GROUP is not called GRP_ASSOC). The parameter value may be cancelled (for instance using PAR_CANCL) without effecting the contents of the group.

  7. A second group is now created to hold the output file names. The two groups are distinguished by the fact that they have different identifiers (stored in IGRP1 and IGRP2).

  8. The user is prompted again, this time for a value for the parameter OUT_FILES and the names obtained are stored in the second group just created. Again the user can give literal files names and/or the names of text files holding other file names. Now that there are two groups, it is possible to use modification to specify the output files. The identifier for the group containing the input files names is given as the second argument of GRP_GROUP, telling the GRP system that if the user specifies output file names using modification (which may not be the case of course), then the output file names are to be derived by modifying the input file names stored in the first group.

  9. In this particular application it is deemed necessary to have equal numbers of input and output files, but GRP imposes no restrictions on the number of strings which can be supplied when responding to a prompt from GRP_GROUP. It is therefore necessary to check the that the two groups contain the same number of elements. A more sophisticated application might seek user intervention to determine how to proceed at this point (either by requesting extra output file names or by ignoring some). Note, if some other error has already been detected (as shown by STATUS having a value other than SAI__OK), then the check on the number of input and output files is irrelevant.

  10. Having stored the input file names in one group and the output file names in another, the application now loops through each pair of input and output file names in turn. An ``index'' I is used to distinguish between different elements within a group. The input file name with index I is retrieved from the first group and the output file name with the same index is retrieved from the second group.

  11. Note, there is a limit to the size of the character string which can be stored in a GRP group. This size is given by the symbolic constant GRP__SZNAM.

  12. A routine is now called which uses the two file names; a typical routine may take data out of the input file, process it and store the results in the output file. The file handling itself would be done within the routine PROC. This example actually makes no assumptions about what the strings stored in the two groups represent (the descriptive strings stored when the two groups were created are of no significance in this application). Although, for clarity, it has been assumed that the strings correspond to file names, they could just as easily have been wavelengths, the names of astronomical objects, calender dates, or just about anything else.

  13. Finally, the groups created by this application are deleted. This is particularly important in applications which run as subroutines within a wider context (such as ADAM applications). There is a limited number of groups available, and if applications forget to delete the groups they have created, then the possibility of exceeding the limit then exists. Note, the groups should be deleted even if the application aborts because of an error, so the statement labelled 999 (to which a jump is made if an error is detected) comes before the calls to GRP_DELET.



next up previous 204
Next: Examples of Possible User Responses
Up: An Example of a Simple GRP Application
Previous: An Example of a Simple GRP Application

GRP Routines for Managing Groups of Objects
Starlink User Note 150
D.S. Berry
21st October 2009
E-mail:ussc@star.rl.ac.uk

Copyright © 2009 Science and Technology Facilities Council