A sort code must provide three routines named init
,
sortin
and finish
. In the case of FORTRAN
sort codes, these are provided as one subroutine called init with two
additional additional entry points. In C sort codes they are provided
as separate functions.
The init routine is called once each time sorting is started (that is each time the user clicks on the read button in the GUI or types sort at the command line. It will typically call any Sunsort initialisation routines that need to be called, initialise any variables and perhaps load data from file.
The sortin routine is called once for each event that is processed. The data is passed through global variables (FORTRAN common block or C extern structs). It is in this routine that the user does the bulk of the processing.
The contents of the sort code are entirely up to the user, though a
typical sort might progress as follows: verify the event is good by
checking its trigger number and the combination of adcs present in it
using the hit patterns, increment singles spectra using a loop,
calculate new pseudo-parameters such as the total energy in a detector
or the position of an event, increment such oned and twod spectra as
necessary, window on oned or twod spectra before finally incrementing
those spectra of physical interest. The path of executable statements
must finally end up at a return
for each event.
The finish routine is executed each time Sunsort stops sorting for whatever reason (barring crashes). This is a good place to print out statistics and do any once only processing that depends on all the data read.
The sort code may signal an error back to Sunsort to tell it to stop sorting. In C this is accomplished by returning a non-zero value. In FORTRAN you instead have to call the subroutine usererror with a non-zero integer parameter. Since only zero/non-zero is tested there is some redundancy here, so it is recommended that users use 1 to mean abort sorting immediately and do not use any other values. That way these other values can be re-used later to mean other things.
Typically an init routine will signal an error if one of it's initialisation files is missing. That way only a few records have been read and the user can correct the problem before continuing.
Signalling an error in the finish routine has no effect at the moment, after all, by the time the finish routine has been called Sunsort is stopping sorting. Still, returning the error may be useful in future, for example, it may stop batch file processing - which it doesn't at the moment.
There are a number of global variables that the user may examine to aid with the sorting. In FORTRAN these are passed through a common block. In C they are passed through extern structs. The details are not important as the include files have the correct declarations in. The list below gives a pseudo-declaration to describe the type of the variable. The first declaration for each variable shows how FORTRAN sees the variable, the second shows how C sees the variable. All these variables are read only with the exception of wrtevt.
See the section on filtering for more information.
In FORTRAN adc(1) onwards hold the value of the appropriate adc for the current event, in C, adcs_.adcs[0] onwards hold the data. To avoid confusion in C, the macro ADC has been defined so that ADC(1) holds the value of the first adc.
For NSF format data, adc(0) is returned with the Daresbury trigger number of the current event, ranging from 1 up to 26. adc(-1) to adc(-8) hold the values of the hit patterns for indirect trigger events. adc(-1) hold the first hit pattern word for adcs 1 to 16, adc(-2) holds the second hit pattern word for adcs 17 to 32 etc. In C, the trigger is in adcs_.triggernos and the hit patterns are in adcs_.bitpattern[0]..adcs_.bitpattern[NOS_BIT_WORDS-1] with the highest numbered element corresponding to the FORTRAN adc(-1).
*vars
section of the sort code. There
values start off as listed in that section, but may be changed by the
user between runs.
In FORTRAN, var(1) holds the value of variable for which varnum equals 1, var(2) the value for which varnum equals 2 etc. In C, vars_.var[0] holds the value of the variable for which varnum equals 1. To avoid confusion, a macro VAR has been defined so that VAR(1) corresponds to FORTRAN var(1).
In2p3 data files store the run number internally near the start of the data file. When Sunsort starts sorting in2p3 data files it initially sets this variable to -1. If it comes across a run number record, it sets this variable to the run number found in the record. Since the run number record comes before all data in a run, if you start sorting a tape file from its start, this variable will be set for all events. If you start a tape file partway through, or if you are sorting a disk file, the variable will not be set.
Since in2p3 data tapes are not ANSI format, they do not have a concept of file names. This run number variable is the only way of identifying which run a file is for. Once data is filtered to disk, then the user will have specified a file name which may be used for identification instead of the run number.
Sunsort provides a number of library routines for use in sort codes. The declarations shown here are provided automatically by the include files. FORTRAN declarations are shown in a compact style similar to that used for ANSI C. Hopefully it's clear what is meant.
This group of functions perform operations that are otherwise difficult in FORTRAN.
result = ((value - low)*base) / (high-low)OK, these operations aren't difficult, and in fact these functions are rarely used.
These routines are for reading and writing values to and from spectra. The bulk of a typical sort code consists of calls to the inc routines.
There are 5 basic actions:
Each action has an associated name. These are:
And for each routine, the channel may be specified in FORTRAN as integer*2, integer, real or double precision, and in C as int or double. For the incv and set calls, the value added or set is of the same type as the channel(s). The val routines always return integer as that is the type the spectra naturally hold. The channel numbers (and values where appropriate) are rounded to the nearest integer, this is equivalent to the FORTRAN function nint or in C ((int) (variable + 0.5)).
Should you need to make a call in which the channel(s) and value (if any) are of different types, then it's most efficient to use the integer version of the call and convert the arguments to integers yourself.
The win routines set a logical variable in FORTRAN depending on whether the specified point is inside or outside the window. In C they return an integer which is zero if the point is outside the window, otherwise it's non-zero.
To make the name of the function start with name of the action, then
append either 1d or 2d depending on which sort of spectrum you want to
access (note that for the win action this must be 2d). Then prepend a
letter indicating the data type if the data type is not integer. These
letters are s
for integer*2, f
for real and
d
for double precision (or C double). This gives the
following list of routines:
The short (integer*2) and float (real) functions are not needed in C as the automatic type promotion takes care of it.
These functions are needed for the data formats that are based on Eurogam format. These are the Demon and Megha formats.
adcnumber @channelwhere number is the array index in the adc() array in decimal counting from 1 (FORTRAN convention) and channel is the Eurogam channel in hexadecimal. A sample file called egmap.dat is in the test_sort directory of the Sunsort distribution.
This call returns zero if all went well, otherwise non-zero. In FORTRAN, the return value is placed in the variable error, in C it is the return value of the function.
Examples of how to use this call are in the test_sort/sorts directory of the Sunsort distribution called egam-f.srt and egam-c.srt.
In the FORTRAN call, the data is copied into the array data(). On entry, len holds the size of the array data(). On exit, len holds the actual amount of data in the group, or a negative number if there wasn't enough room in the array.
In the C call, NULL is returned if the group was out of range. Otherwise a pointer to a structure is passed back. The structure has at least the following elements:
int group_len; unsigned short *group_ptr;If group_len is non-zero then group_ptr points to the data for the group, that is group_ptr[0] holds the first piece of data for the group. If group_len is zero then there was no data for this group in this event and the value of group_ptr is undefined. Note that neither the data pointed to by pointer returned from the egroup call, nor the data pointed to by group_ptr should be written to.