Example is always more efficacious than precept.Lives of the English Poets vol. ii
Samuel Johnson
This section will walk you through the Fortran source code for a simple application which uses the CAT library to write a small catalogue. First, however, a few preliminaries.
explains
how to access these files. It is worth your while printing out and
examining copies of both files. The comments included in the files
should be sufficient to explain the purpose of each constant. CAT_PAR contains general constants pertaining to the CAT library.
CAT_ERR contains constants corresponding to the various error
codes which can be set by the CAT library. If your application needs
to access one of these values you should always use the
appropriate symbolic constant; never hard-code the actual
value into your code. The values may (and probably will) change in
subsequent releases of the CAT library.
This scheme is adopted in both the routines to get a value from a catalogue and those to put a value to a field in a catalogue. It is adopted to avoid any possible ambiguity in interpreting null values.
When a null value is obtained from a catalogue the actual datum returned will be the ADAM `bad' value for the appropriate data type (where one is available). This procedure facilitates passing values obtained from CAT into other ADAM subroutines. It means, however, that the null value returned through the CAT interface is not necessarily the same as the representation of the null stored in the catalogue. Existing catalogues, for example FITS tables from external sources, can come with a variety of values used to represent null values. The necessary checks and substitutions are performed automatically and invisibly within the catalogue-format specific parts of the CAT library. Your application will simply see the appropriate ADAM `bad' value.
Not all catalogues support null values in all their columns. If a column does not support null values then the null value flag will always be returned set to .FALSE.
The treatment of null values is described in greater detail in
Section
. In particular, Section
prescribes
how applications should handle null values.
We are now ready to examine a simple application which uses the CAT library. We will use one of the example applications released with the library, EXAMPLE_WRITE. This example creates and writes values to a small catalogue. I strongly recommend that you print out a copy of the source code and refer to it as you work through the example. The source code is available in file:
This example program is simpler than a real application. Starting at the beginning, the first thing to notice about the application is that, because it is an ADAM A-task, at its top level it is a subroutine, not a main program:
SUBROUTINE EXAMPLE_WRITE (STATUS)
The status argument is used to keep track of the success of the application as it proceeds with its task.
*+
* Name:
* EXAMPLE_WRITE
.
.
.
After the ADAM prologue comments the CAT symbolic constants are INCLUDEd. Some of the constants defined in this file will be used by the application.
* Global Constants:
INCLUDE 'SAE_PAR'
INCLUDE 'CAT_PAR'
The various variables used in the application are defined next.
* Status:
INTEGER STATUS ! Global status.
* Local Variables:
INTEGER
: CI, ! Catalogue identifier.
: QII, ! Identifier for a real parameter.
: QIR, ! Identifier for a real parameter.
: QIC, ! Identifier for a character parameter .
: FII, ! Identifier for an integer column (or field).
: FIR, ! Identifier for a real column (or field).
: FIC, ! Identifier for a character column (or field).
: LOOP ! Loop index.
INTEGER
: VALI ! Integer value.
REAL
: VALR ! Real value.
CHARACTER
: VALC*10 ! Character value.
LOGICAL
: NULI, ! Null flag corresponding to VALI.
: NULR, ! " " " " VALR.
: NULC ! " " " " VALC.
*.
The first executable statement is the usual check that the status is ok. This check is mandatory in ADAM applications.
IF (STATUS .EQ. SAI__OK) THEN
Once it is out of the way the application proper can start. It starts with a call to CAT_CREAT:
CALL CAT_CREAT ('CNAME', CI, STATUS)
This subroutine will create a new catalogue, whose name it obtains from the ADAM parameter system (in practice the user will be prompted for it)3. The first argument of CAT_CREAT is the name of the ADAM parameter which will supply the catalogue name. The remaining two arguments are returned by CAT_CREAT; CI is the identifier for the catalogue. We will use this variable to refer to the catalogue throughout the application. STATUS is the running status argument which is usual in ADAM libraries. If the routine has succeeded its value is SAI__OK.
After CAT_CREAT has executed successfully a new catalogue has been created, but no columns or parameters have been defined for it, and it contains no data. The next step is to define some columns. The first column defined is an INTEGER column called COLI. Subroutine CAT_PNEW0 is used for this task:
CALL CAT_PNEW0 (CI, CAT__FITYP, 'COLI', CAT__TYPEI, FII,
: STATUS)
The first argument, CI, identifies the catalogue to which the
new column belongs. The second argument tells CAT_PNEW0 that it
has to create a new column; this argument should always be CAT__FITYP when a column is to be created. The third argument is the
name of the column, COLI in the present case, and the fourth
argument defines its data type. There are symbolic constants defined in
CAT_PAR for each of the data types supported by CAT. COLI
is an INTEGER column, so the code for an INTEGER is used. The codes for
the different data types are listed in Table
.
The fifth argument, FII, is returned rather than given and is an identifier for the column; subsequent references to the column will be via this identifier. The final argument is the usual ADAM running status.
The mandatory information which you must supply to define a column is:
the catalogue to which it belongs, its name and its data type. All these
values are specified using routine CAT_PNEW0. However, as
explained in Section
, a column is defined by a set of
attributes, of which the name and data type are but two, albeit
mandatory ones. Section
lists all the attributes for a
column. If you do not specify the remaining attributes default
values are adopted for them. You can, however, supply your own values to
over-ride the defaults. The next line is an example of doing so.
CALL CAT_TATTC (FII, 'COMM', 'Integer column', STATUS)
This routine is one of a family of similar routines, one for each data type (CAT_TATTC for attributes of data type CHARACTER, CAT_TATTI attributes of type INTEGER etc). Here it is used to set the comment attribute, COMM of column FII to the value `Integer column'. Other attributes of column COLI could have been set in the same way, but in this example they are not, and the defaults are adopted4.
Two additional columns are created in the same way; the REAL column COLR and the CHARACTER column COLC. Note that in the case of COLC the CHARACTER size attribute CSIZE is set using routine CAT_TATTI.
CALL CAT_PNEW0 (CI, CAT__FITYP, 'COLR', CAT__TYPER, FIR,
: STATUS)
CALL CAT_TATTC (FIR, 'COMM', 'Real column', STATUS)
CALL CAT_PNEW0 (CI, CAT__FITYP, 'COLC', CAT__TYPEC, FIC,
: STATUS)
CALL CAT_TATTC (FIC, 'COMM', 'Character column', STATUS)
CALL CAT_TATTI (FIC, 'CSIZE', 10, STATUS)
An important restriction to remember is that columns must be created, and their attributes set, before any rows of data are written to the catalogue. Once a table of values have been written to a catalogue the details of its existing columns are frozen and no new columns can be created for it.
After creating the columns, some parameters are created. The first of these is the INTEGER parameter PARI. It is created with the same routine that was used to create the columns, CAT_PNEW0:
CALL CAT_PNEW0 (CI, CAT__QITYP, 'PARI', CAT__TYPEI, QII,
: STATUS)
Again the first argument is the catalogue identifier. The second argument indicates that a parameter is to be created; this argument should always be set to CAT__QITYP when a parameter is to be created. The remaining arguments are exactly the same as they were for creating a column: PARI is the parameter name, CAT__TYPEI the data type and QII and STATUS are the identifier for the parameter and the running status, respectively.
As for columns, only the minimum, mandatory attributes for the parameter
are set with CAT_PNEW0, and default values are adopted for the
remaining attributes. Section
lists the attributes of a
parameter. Also just like columns, the attributes of parameters can be
set using the CAT_TATT
t
family of routines (where t = C for CHARACTER attributes, I for INTEGER etc). In the
example CAT_TATTC is used to set the comments attribute, COMM of
parameter PARI and CAT_TATTI is used to set the value
attribute VALUE. The latter point is worth remembering; having created
a parameter with CAT_PNEW0 it is necessary to use one of the CAT_TATT
t
routines to set its value, and the routine chosen
should correspond to the data type of the parameter5.
CALL CAT_TATTC (QII, 'COMM', 'Integer parameter', STATUS)
CALL CAT_TATTI (QII, 'VALUE', 23, STATUS)
Two additional parameters are created; the REAL parameter PARR and the CHARACTER parameter PARC. Note that, as was the case for columns, for the CHARACTER parameter PARC the CHARACTER size attribute `CSIZE' must be set using CAT_TATTI.
CALL CAT_PNEW0 (CI, CAT__QITYP, 'PARR', CAT__TYPER, QIR,
: STATUS)
CALL CAT_TATTC (QIR, 'COMM', 'Real parameter', STATUS)
CALL CAT_TATTR (QIR, 'VALUE', 42.0, STATUS)
CALL CAT_PNEW0 (CI, CAT__QITYP, 'PARC', CAT__TYPEC, QIC,
: STATUS)
CALL CAT_TATTC (QIC, 'COMM', 'Character parameter', STATUS)
CALL CAT_TATTI (QIC, 'CSIZE', 20, STATUS)
CALL CAT_TATTC (QIC, 'VALUE', 'Example string', STATUS)
Note that, unlike columns, parameters can be created at any stage while writing a catalogue. They do not have to be created prior to writing the table of values for the catalogue.
Once the parameters have been created the example starts a loop which will write the table of values.
DO LOOP = 1, 25
In the CAT interface the basic method of writing (and reading) a catalogue is one row at a time. Each increment of the loop will correspond to a separate row of the catalogue, and thus in total twenty-five rows will be written, numbered from one to twenty-five.
The first few lines of code inside the loop are concerned with inventing values to write to the catalogue. The next few lines set the null value flags (all the rows contain non-null values, except row ten, where the flags are set to null). In a real application, of course, these values would not be invented, but would either be the results of a calculation or read from an external file.
VALI = LOOP
VALR = 2.3E1 + REAL(LOOP)
VALC = ' '
WRITE(VALC, 4000) LOOP
4000 FORMAT(' Loop ',I3, '%')
NULI = .FALSE.
NULR = .FALSE.
NULC = .FALSE.
*
* Make all the columns contain null values for row 10.
IF (LOOP .EQ. 10) THEN
NULI = .TRUE.
NULR = .TRUE.
NULC = .TRUE.
END IF
The line:
CALL CAT_PUT0I (FII, VALI, NULI, STATUS)
writes a single value to column COLI. FII is the column
identifier, VALI and NULI the value and null value flag
respectively. STATUS is, of course, the running status. CAT_PUT0I is one of the family of CAT_PUT0
t
routines,
with one routine per data type. (I for INTEGER, C for
CHARACTER etc). Thus there are corresponding calls to write the REAL and
CHARACTER columns COLR and COLC:
CALL CAT_PUT0R (FIR, VALR, NULR, STATUS)
CALL CAT_PUT0C (FIC, VALC, NULC, STATUS)
CAT has the concept of the `current row buffer', which is an internal
copy of the row of the catalogue which it is working on currently. The
CAT_PUT0
t
routines put fields to the current row buffer
(and the corresponding CAT_GET0
t
routines read values from
it).
CALL CAT_RAPND (CI, STATUS)
Writes out the current row buffer for catalogue CI to the actual catalogue file, appending it to the end of the catalogue. The internal current row buffer is initialized ready to receive new values, and the internal count of the actual catalogue row number to which the current row buffer corresponds is incremented by one. That is, CAT_RAPND takes care of writing the current row buffer to the catalogue and readies CAT to receive values for a new current row buffer. When a catalogue is created the current row buffer is initialized automatically and the row number to which it corresponds is set to one.
Thus a loop with one increment corresponding to one row in the
catalogue and containing calls to CAT_PUT0
t
routines to put
values to the current row buffer and a call to CAT_RAPND to
append the current row buffer to the catalogue is all that is necessary
to write a table of values to a catalogue. The current row has been
written, so the loop generating each row can now terminate:
END DO
There is one final call to a CAT routine:
CALL CAT_TRLSE (CI, STATUS)
This call `releases' catalogue identifier CI and closes the corresponding catalogue. Identifiers to items within the catalogue, such as the various columns and parameters, are also released. Any remaining values are written to disk, the files are closed etc. The creation of the catalogue is complete. Finally, if all has succeeded, the application reports a message and then terminates.
IF (STATUS .EQ. SAI__OK) THEN
CALL MSG_OUT (' ', 'Catalogue created successfully.',
: STATUS)
ELSE
CALL ERR_REP ('EXAMPLE_WRITE_ERR', 'Failed to create '/
: /'catalogue.', STATUS)
END IF
END IF
END
Having worked through this example application you might like to try it out. Type:
example_write
You will be prompted for the catalogue name. Reply, for example:
test.fit
After a couple of moments the message `Catalogue created successfully.' should appear and a binary FITS table called test.fit should have been created in your current directory. You can examine its contents using the xcatview catalogue browser in CURSA (see SUN/190[3]) or the listout utility in CAT-EXAMPLES. For the latter simply type:
listout
and answer the prompts (see Section
for details).
Another example program is available which reads back the catalogue created by EXAMPLE_WRITE. It is called EXAMPLE_READ and the source code is available in file:
You might like to print out a copy and try to understand it. If you have followed the discussion for EXAMPLE_WRITE you should be able to do so without any difficulty.
CAT [1ex