Using Daphne with GammaSphere and GammaSphere Tapes Page 1 1 Introduction Daphne has been modified to work with GammaSphere format data. Data can be supplied in two ways: - From GammaSphere format data tapes Use the Daphne $TAPE/IN/GS command. - From the network Use the Daphne $ACQ/GS (or $ACQ/GS/DEBUG) command with GammaSphere (and programs which imitate the GammaSphere network protocol) to sort GammaSphere format event buffers. The GammaSphere network protocol is a simple protocol based on TCP/IP UDP packets. Daphne provides additional support to GammaSphere users with a subroutine ("gsUnpack") which can be called from a Daphne user-function to unpack a GammaSphere event into a format which is easy to use with Fortran code. This function can insulate the user's code from future changes in the GammaSphere event format: instead of the user having to rewrite his own code, he can simply relink his program with the new version of the gsUnpack routine. Using Daphne with GammaSphere and GammaSphere Tapes Page 2 2 Reading a GammaSphere Tape 2.1 Mount the Tape To ready a GammaSphere data tape for replay: $ TAPE/IN/GS ANPH19$MKA500: This starts up the GStape process which: - Performs the equivalent of a VMS $MOUNT command - Reads the tape header - Reads the file header for the first file on the tape - Places date and time from headers in the banner - Displays tape and file information at the terminal: GStape: Exp: gs74; 203 48Ca + 150Nd 06:54:12 10/13/96 recorded on tape unit 5 GStape: Positioned at File: 1 Run: 41 Title: Still newer gains, gs74_hi_6; Tgt postn 4720 2.2 Positioning the Tape You can use the following commands to position the tape: - $ FND the_run_number This searches forward for a matching run number. Many GS data tapes contain multiple files with the same run number. They can be distinguished by their file number. - $ SKP - $ SKP the_number_of_files Skips forwards (or backwards for negative values) the specified number of files. An argument of zero causes the tape to be positioned at the start of the current file. A $SKP with no arguments advances the tape to the next file. - $ BSP - $ BSP the_number_of_files A backspace command skips backwards (or forwards for negative values) the specified number of files. A value of zero positions the tape at the start of the current file. A backspace command with no arguments positions the tape to the Using Daphne with GammaSphere and GammaSphere Tapes Page 3 start of the current file. - $ REW - $ REW/IN Rewinds the tape and positions it at the start of the first file. The $REW command is the only way to recover from an 8mm tape which is "stuck" in the end-of-volume zone. 2.3 End of Recorded Data Normally, the end of recorded data on a tape is indicated by two consecutive end-of-file markers (the "end-of-volume")., NOTE The end-of-volume is different from the end-of-tape. The end-of-tape condition indicates that the end of the physical tape is near, but leaves space for a few additional writes. Many tapes prepared at GammaSphere have only a single end-of-file mark at the end of the recorded data. In these cases, when GStape tries to read the file header following the last file mark it will receive an I/O error. GStape assumes that an I/O error while reading a file header indicates the end of recorded data. In contrast, an I/O error while reading event data causes the data block to be ignored and reading to continue with the next block on the tape. GammaSphere data tapes which have been copied using VMS utility programs (including the Daphne program dapexe:TapeCopy) will have two end-of-file marks at the end of recorded data. However, this may be a mixed blessing because of the next item. 2.4 The End-Of-File Zone The end-of-volume condition receives special support in the hardware and operating system in order to prevent a program from accidentally skipping past the end-of-volume. For instance, an effort to skip 1000 files will terminate at the end-of-volume with a special status. Normally, it is possible to leave the end-of-volume zone between the tape marks by doing a read forwards or read backwards. However with 8mm tape drives on AXP/VMS 6.2 (and perhaps other combinations of equipment and software) this does not work: the only way to recover from a tape which is stuck in the end-of-volume zone is to do a Using Daphne with GammaSphere and GammaSphere Tapes Page 4 rewind. 2.5 Supported Record Types The GammaSphere documentation mentions seven record types. All seven types of records are passed to the sort program for use by the GammaSphere block-handler (not described in this note) and an OPTIONAL user supplied subroutine. Only event data records (type 3) are actually sorted. 2.6 Replay The user starts the replay of data from tape (R-D-T) with the command: $ RDT If you have compiled and linked your user-function with the /DEBUG option and wish to debug your user-function use the command: $ RDT/DEBUG. - GStape updates the Daphne banner information The "comment" field is created from the file number (not the run number), and the first 60 or so characters of the run information in the file header. The "run number" field is copied from the run number field of the file header. Note: there may be several files on a GS tape with the same run number. - The following OPTIONAL user-function entry points are called: For more information see the section on the user-function. - The user initialization routine ("userInit") - The tape header routine ("gsTapeHeader") - The file header routine ("gsFileHeader") - The event header routine ("gsEventBuffer") - The user's block handler routine ("isGoodBlock") When GStape reaches the end-of-file or the user enters $STP GStape will display the number of blocks read on the terminal. $ stp GStape: Run cancelled - stopped at block 468 of file (does not count 2 header records) Sorting stopped - 470 records read (of those read 2 were NOT sorted) Using Daphne with GammaSphere and GammaSphere Tapes Page 5 The two header records are the tape header and the file header, neither of which is sortable. This can also be seen with the $CNT command: $ cnt Events read and sorted: 89,389 Records read by sort: 470 Records skipped by sort: 2 (of those records read) A GammaSphere block of event data is always 16 kBytes (16,384 bytes). When the sort engine stops it calls the user's OPTIONAL exit routine, giving it the opportunity to write out summary information. If replay is stopped before the end-of-file is reached one can resume it by issuing another $RDT command. Previously, Daphne did not allow replay to resume from the middle of a file. When starting from the middle of a file, copies of the tape header and file header are still passed to the sort program for use by the "block handler" and OPTIONAL user routines. Using Daphne with GammaSphere and GammaSphere Tapes Page 6 3 Reading Network Data - The GammaSphere UDP Receiver The GammaSphere UDP Receiver ("GSudp") is started automatically by the $ACQ/GS command and terminates when sorting is stopped with the $STP command. As it is easy to forget the /GS qualifier, a user may want to make the following definition: $ ACQ:==ACQ/GS 3.1 The UDP Port Number GSudp listens on a "port". The port is determined by: - The VMS logical name "DAP$GSUDP_PORT" - Otherwise the VMS logical name "DAP$GSUDP_PORT_DEFAULT" - Otherwise port 1101 The logical names may NOT be defined in the process logical name table because the GSudp process runs as a subprocess. You should define them in the JOB, GROUP, or SYSTEM logical name table as appropriate. Only one GSudp process can be active on a given port at a time. To have multiple GSudp processes on a single machine one of the users must over-ride the default. 3.2 Fragmentation of Data Blocks The GammaSphere event data is organized into blocks of 16 kBytes (16,384 bytes) exceeding the MTU ("maximum transmission unit") of almost all network hardware, including ethernet. Ethernet is limited to packets of 1500 bytes. For this reason the UDP sender must break up the data block into "fragments". At present the UDP sender sends a data block in 17 fragments of 1024 bytes each. I don't understand why the fragments are not 1500 bytes. The simple-minded GSudp expects all the fragments to arrive in order and combines them to recreate the original data block. If any fragment fails to arrive in the proper order all the fragments for that block are discarded. The program continues to receive fragments, looking for the first fragment of a new block. Unlike TCP, UDP does not try to create a perfect data stream or attempt flow control. The specification for UDP specifically allows for UDP packets to be discarded by network software at whim or for reasons such as network congestion, insufficient buffer space, busy network interface, insufficient CPU time to process, higher priority Using Daphne with GammaSphere and GammaSphere Tapes Page 7 traffic, etc. In return for using the unreliable UDP protocol GammaSphere can sometimes exploit the broadcast capability of ethernet to transmit data to several workstations simultaneously. Since data from GammaSphere is recorded directly on the front-end system on 8mm tape, it was deemed acceptable to lose some data in the on-line analysis phase in order to gain a many-fold improvement in bandwidth from the front-end to the analysis workstations. 3.3 GammaSphere UDP Statistics From the above discussion it is clear that it is important to know how many data blocks are being lost due to lost fragments. This information is available from the $CNT/FULL command (or $CNT/GSudp) and from GSudp at the time it exits: Using GammaSphere UDP Complete data blocks received: 318 Fragments received: 5,433 Fragments discarded: 27 Percent fragments discarded: 0.5 % Unexpected fragment error 2 The percentage of fragments discarded will vary depending on CPU load, network activity, depth of buffering, and the rate at which data is being sent. Below is a list of all the error conditions reported by the GSudp: Fatal - Can't continue Socket creation error Socket bind error Get socketName error Minor and routine - Discard packet(s) and continue Get 1 of N - recvfrom error Get rest of N - recvfrom error Unexpected fragment error Get rest of N - seq error Unexpected - Shouldn't happen under normal conditions Event buffer overflow error Empty fragment error Checksum failure error Unrecognized block record type Using Daphne with GammaSphere and GammaSphere Tapes Page 8 3.4 Record Types Supported The GammaSphere documentation mentions seven types of records: only event data (record type 3) is transmitted in this fashion. It is not possible for Daphne to display or record the run title, experiment title, run start, run stop, or other "administrative" information when the data is transmitted in this fashion. Neither is there any way for the GSudp to know when a run ends except by having the user give the $STP command. In my opinion this is an over-sight. Using Daphne with GammaSphere and GammaSphere Tapes Page 9 4 The User-function A GammaSphere user-function is a Daphne user-function with additional OPTIONAL entry points which are invoked by the Daphne sort engine at certain times during replay. When a user omits these optional elements from his user-function a default version (just a "return" statement) is supplied by the Daphne user-function library ("dapexe:DapUserFuncLib.olb") courtesy of the VMS linker. 4.1 Example of a Simple GammaSphere User-function The following simple, but complete, user-function histograms the number of clean Ge detectors. It assumes there is a 1D histogram with the name "clean_ge" and makes use of the gsUnpack routine to unpack the event into a Fortran common block for convenient access. +---------------------------------------------------------------------+ | subroutine user(eventType,numberOfWords,ev) | | implicit none | | c | | integer*4 eventType ! not used with GS | | integer*4 numberOfWords ! 16 bit words in event | | ! excludes GS word count field | | integer*2 ev(*) ! event vector | | ! excludes GS word count field | | c | | c gsUnpack.inc defines common block interface between | | c the user-function and "gsUnpack" | | c | | include 'dapexe:gsUnpack.inc' | | c | | c gsRecords.inc defines common block interface between | | c the GammaSphere block handler and the user-function | | c | | include 'dapexe:gsRecords.inc' | | c | | c number of the histogram for clean Ge | | c | | integer*4 h1CleanGe | | integer*4 status | | integer*4 gsUnpack | | c | | status=gsUnpack(numberOfWords,ev) | | c | | c subscript for ext detector info in event vector given by | | c "extDetectorPos" | | c If OK then increment clean Ge histogram channel | | c | | if (status .eq. 0) then | | call h1Inc(h1CleanGe,len_clean) | | endif | | c | | return | Using Daphne with GammaSphere and GammaSphere Tapes Page 10 | c | | ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc | | c | | c this example needs to supply the optional userInit routine | | c | | entry userInit | | call h1Number('clean_ge',h1CleanGe) | | write (6,*) 'UserInit: histogram clean_ge is #',h1CleanGe | | return | | c | | ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc | | c | | c this example chooses to supply the optional userEx routine | | c | | entry userEx | | write (6,*) 'UserEx: Finished processing:' | | write (6,*) 'File: ',the_file_header.FileNumber | | write (6,*) 'Run 1: ',the_file_header.run_title1 | | write (6,*) 'Run 2: ',the_file_header.run_title2 | | return | | c | | ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc | | c | | c this example chooses to supply the optional gsFileHeader routine | | c | | entry gsFileHeader | | write (6,*) 'GS Tape/File Header:' | | write (6,*) 'Date: ',the_tape_header.date | | write (6,*) 'Time: ',the_tape_header.time | | write (6,*) 'Exp 1: ',the_tape_header.exp_title1 | | write (6,*) 'Exp 2: ',the_tape_header.exp_title2 | | write (6,*) 'Run: ',the_file_header.RunNumber | | write (6,*) 'File: ',the_file_header.FileNumber | | write (6,*) 'Run 1: ',the_file_header.run_title1 | | write (6,*) 'Run 2: ',the_file_header.run_title2 | | return | | end | +---------------------------------------------------------------------+ Using Daphne with GammaSphere and GammaSphere Tapes Page 11 4.2 The Optional Entry Points The GammaSphere documentation mentions seven record types. For each record type the user can supply an OPTIONAL subroutine to perform an operation appropriate for that type of record when it is passed to the sort engine. - subroutine gsTapeHeader(a_tape_header) record /TAPE_HEADER/ a_tape_header - subroutine gsFileHeader(a_file_header) record /FILE_HEADER/ a_file_header - subroutine gsEventBuffer(an_event_buffer) record /EVENT_BUFFER/ an_event_buffer The gsEventBuffer routine is NOT meant for sorting event data. It is meant to allow processing of the event header (not event data) which contains important information such as the GammaSphere "mode" bits. NOTE The gsTapeHeader and gsFileHeader routines will never be called when data is being received by GSudp because GammaSphere does NOT send tape header or file header records. The following routines exist only for completeness: these record types have been observed neither in captivity nor in the wild. - subroutine gsLogRecord(a_log_record) record /log_record/ a_log_record - subroutine gsScalerRecord(a_scaler_record) record /scaler_record/ a_scaler_record - subroutine gsCalibrationRecord(a_calibration_record) record /calibration_record/ a_calibration_record - subroutine gsSourceRecord(a_source_record) record /source_record/ a_source_record - subroutine gsHistorgramRecord(a_histogram_record) record /histogram_record/ a_histogram_record The records which are arguments to these functions are defined in a VMS Fortran structure in the include file "dapexe:gsStructures.inc'. Excerpts from this file appears at the end of this note. The names of the structures are the same as the names of the corresponding struct in the GammaSphere C language header file. Using Daphne with GammaSphere and GammaSphere Tapes Page 12 There is a second way for a user-function to get information from the tape header or file header. This second technique is used in the example above. A Daphne supplied routine copies the tape header and file header to common blocks where they can be accessed at a later time. These common blocks are defined in the include file dapexe:gsRecords.inc. An excerpt from the file is listed here for convenience: +-----------------------------------------------------------------------+ | include file dapexe:gsRecords.inc | +-----------------------------------------------------------------------+ | include 'dapexe:gsStructures.inc' | | | | common /gs_tape_header_common/ the_tape_header | | common /gs_file_header_common/ the_file_header | | | | record /TAPE_HEADER/ the_tape_header | | record /FILE_HEADER/ the_file_header | +-----------------------------------------------------------------------+ 4.3 Linking the User-function A GammaSphere user-function MUST be linked with special Daphne subroutines in order for the features described in this memo to work: $ @dapexe:gsUserFunc.lnk the-user-function link-options For example: $ @dapexe:gsUserFunc.lnk myUserFuntion /DEBUG If you link using the standard Daphne command file "dapexe:dapuserfunc.lnk" you will get an error message for the undefined reference "link_using_gsuserfunc_dot_lnk". If you accidentally link using the MSU command file "dapexe:msuUserFunc.lnk" you will receive an error message for the undefined reference "welcome_to_east_lansing_michigan". That's just a joke. Actually, you will receive an error message at execution time telling you that the the sort program is expecting data of type "MSU" while the data appears to be of type "GS". 4.3.1 The gsUnpack Routine The gsUnpack routine unpacks a GammaSphere event into Fortran common blocks which are in a format convenient for use by the user-function. At the tail end of the event vector, following data from the GammaSphere detector, is any data from the external detectors. If there are external detector data in the event then the common block variable "extDetectorPos" is set so that eventVector(extDetectorPos) Using Daphne with GammaSphere and GammaSphere Tapes Page 13 is the first word of an integer*2 vector of external detector data embedded in the event vector. If there is no external detector data then extDetectorPos is set to zero. The number of words of external detector data (if present) is: external_detector_words = words_in_the_event - external_detector_position + 1 The status code returned by gsUnpack are: - gsUnpack_badWC=1 The word count field at the start of the event is less than 1. - gsUnpack_badLastWord=2 The last word of the event is not 0xffff as expected. - gsUnpack_exceedSane=3 There are more than "gsUnpackMaxSane" detectors in the event. - gsUnpack_mismatch=4 After unpacking the event the routine found that the number of words it had unpacked in the event didn't match the word count in the event header. This indicates that there is some kind of mismatch between the actual format of the event and the format expected by gsUnpack. - gsUnpack_badExternal=5 Any external data is supposed to be preceded by a word containing 0xff00. - gsUnpack_badID=6 The detector ID is not between 1 and 110. It is set to zero, but the routine continues to unpack the rest of the event. For all errors (except gsUnpack_badID) the unpacking of the event is halted and the gsUnpack routine returns immediately. For gsUnpack_badID the routine continues to unpack the event. Using Daphne with GammaSphere and GammaSphere Tapes Page 14 The following simple example of a GS user-function calls gsUnpack and then histograms the energy of each pairwise combination of Ge detectors which have fired without a BGO shield hit. Both the upper and lower triangles of the matrix are incremented. The Ge energy values are divided by 8 in order to reduce the size of the histogram. +----------------------------------------------------------------------+ | subroutine user(eventType,numberOfWords,ev) | | implicit none | | c | | integer*4 eventType ! not used with GS | | integer*4 numberOfWords ! 16 bit words in event | | ! excludes GS word count field | | integer*2 ev(*) ! event vector | | ! excludes GS word count field | | c | | c gsUnpack.inc defines common block interface between | | c the user-function and "gsUnpack" | | c | | include 'dapexe:gsUnpack.inc' | | c | | c gsRecords.inc defines common block interface between | | c the GammaSphere block handler and the user-function | | c | | include 'dapexe:gsRecords.inc' | | c | | integer*4 status | | c | | c number of the histogram for energy vs. energy | | c | | integer*4 h2EE | | c | | integer*4 i | | integer*4 j | | c | | integer*4 gsUnpack | | c | | status=gsUnpack(numberOfWords,ev) | | if (status .eq. 0) then | | do i=1,len_total-1 | | if (geBit(i) .and. .not. bgoHit(i)) then | | do j=i+1,len_total | | if (geBit(j) .and. .not. bgoHit(j)) then | | call h2inc(h2ee,eHi(i)/8,eHi(j)/8) | | call h2inc(h2ee,eHi(j)/8,eHi(i)/8) | | endif | | end do | | endif | | end do | | endif | | c | | return | Using Daphne with GammaSphere and GammaSphere Tapes Page 15 | c | | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc | | c | | c this demo needs to supply the optional userInit routine | | c | | entry userInit | | call h2Number('EE',h2EE) | | return | | end | +----------------------------------------------------------------------+ Using Daphne with GammaSphere and GammaSphere Tapes Page 16 The all-important include file "gsUnpack.inc" which describes the common blocks into which the event is unpacked is at the end of this document. +-----------------------------------------------------------------------+ | GammaSphere Only | +-----------------------------------------------------------------------+ | integer*4 function gsUnpack(nw,ev) | | | | Unpack a standard GammaSphere event | | Adopted for Fortran from Torben's C version | | Places almost all information about the event | | in common blocks declared by "gsUnpack.inc" | | | | If there are N modules that fire: the information is placed in the | | first N elements of the vectors for that information: | | | | e.g. id(1) is the detector ID for the first module in the event | | id(2) is the detector ID for the second module in the event | | id(3) contains the detector ID for the third module | | | | geHit(1) indicates a hit on the detector given by id(1) | | geHit(2) indicates a hit on the detector given by id(2) | | geHit(3) indicates a hit on the detector given by id(3) | | | | len_total is the total number of modules in the event vector | | | | See dapexe:gsUnpack.inc (or the end of this note) for the names | | of the fields used by gsUnpack. | | | | function value - output/integer*4 | | | | gsUnpack_badWC: 1 = number of words in event .le. 0 | | gsUnpack_badLastWord 2 = last word of event .ne. 0xffff | | gsUnpack_exceedSane 3 = more than maxSane detectors in event | | gsUnpack_mismatch 4 = event desc. doesn't match event length | | gsUnpack_badExternal 5 = ext. det. data not preceded by 0xff00 | | gsUnpack_badID 6 = detector id .lt. 1 .or. .gt. 110 | | sets the detector id to 0 | | continues unpacking entire event | | return error code | | | | nw - input/integer*2 | | number of words in event vector | | | | ev - input/integer*2 array | | event vector | +-----------------------------------------------------------------------+ The source code for gsUnpack is in dapexe:gsUnpack.for. Using Daphne with GammaSphere and GammaSphere Tapes Page 17 4.3.2 Reporting gsUnpack Errors Routine gsUnpack returns a status value of zero on success. A user-function does not normally have to report these errors because the gsUnpack routine keeps track of them and reports them in two ways. There are separate error counters for each kind of error detected by gsUnpack. On the first, tenth, hundredth, etc. occurrence of an error it is reported on the terminal. The user can disable this reporting by calling gsUnpackSetReportErrors(.false.). +-----------------------------------------------------------------------+ | GammaSphere Only | +-----------------------------------------------------------------------+ | | logical*4 function gsSetReportErrors(trueOrFalse) | | | | Enables or disables the reporting of errors on the 1,10,100,... | | occurrence. The errors are counted whether reporting is | | disabled or not. | | | | The current version of gsUnpack does not provide any way to | | suppress the error summary that occurs at the end of the sort. | | | | function value - output/logical*4 | | the value of the "report errors flags" | | before it was changed to the new value | | | | trueOrFalse - input/logical*4 | | .true. enables reporting | | .false. disables reporting | | (does NOT disable counting) | +-----------------------------------------------------------------------+ Using Daphne with GammaSphere and GammaSphere Tapes Page 18 4.3.3 The Maximum Number of Detectors (gsUnpackMaxSane) One of the errors reported by gsUnpack is an event with "too many" detectors. If the number of detectors in an event exceeds gsUnpackMaxSane then unpacking of the event stops and a non-zero status code is returned by gsUnpack. The default value for gsUnpackMaxSane is currently 30. +----------------------------------------------------------------------+ | GammaSphere Only | +----------------------------------------------------------------------+ | integer*4 function gsUnpackSetMaxSane(newSaneValue) | | | | Sets a limit on the number of detectors which are allowed | | in an event before it is rejected by gsUnpack. | | | | function value - output/integer*4 | | previous value of gsUnpackMaxSane | | | | newSaneValue - input/integer*4 | | new value of gsUnpackMaxSane | +----------------------------------------------------------------------+ 4.4 Using the VMS symbolic debugger For information on using the VMS symbolic debugger with a Daphne user-function see the Daphne "Guide to Replay". 4.5 Performance Impact of Unaligned Data This topic is discussed in detail in the "Guide to Replay", but is so important that it bears repetition: +--------------------------------------------+ | The AXP will allow the user to access data | | which is not properly aligned. However, | | the impact on performance is ENORMOUS. | +--------------------------------------------+ The key to detecting this potential catastrophe is: DBG> set break/unaligned Using Daphne with GammaSphere and GammaSphere Tapes Page 19 4.6 Avoid Use of integer*2 Variables on AXP The AXP architecture is optimized for 64 bit operations, has good support for 32 bit operations, and is awkward with 16 bit quantities. Users should avoid using integer*2 variables when integer*4 variables would be just as easy to use. 4.7 Sign Extension of 16 bit Hexadecimal Constants If you use 16 bit hexadecimal constants in your Fortran code remember that Fortran sign extends integer*2 variables to 32 bits and 64 bits as appropriate. You can avoid this problem by coding at least 5 hexadecimal digits: instead of coding 'ffff'x use '0ffff'x. Using Daphne with GammaSphere and GammaSphere Tapes Page 20 5 Miscellaneous 5.1 Alternating Use of GS UDP Receiver and GS Tape Reader It is possible to alternate between GStape and GSudp to analyze data, but not while sorting is active. In particular, it is not necessary to unload the tape or kill GStape in order to start the GSudp process. 5.2 No Output in GammaSphere Format Daphne can create subsets of events and save them in a data file. However, the data files will be in Daphne format, not GammaSphere format. See the Daphne "Guide to Replay" on how to select a subset of events for a new data file. 5.3 Byte Swapping from Sun to VAX or AXP Byte Order All GammaSphere data, at this time, is created in Sun Sparc byte order which is different from the VAX and AXP byte order. A 16 bit number with the hexadecimal value "1234" on a Sun would appear to have the hexadecimal value "3412" on a VAX or AXP. Daphne automatically compensates for this when it reads GammaSphere data from tape or receives it over the net with the GSudp. Daphne contains carefully written code to perform this operation efficiently. There are separate versions for the VAX and AXP and different versions depending on the alignment of the data - four versions altogether. Users processing GammaSphere data using their own software on a VAX or AXP should use these routines rather than a naive Fortran or C function if concerned with performance. +----------------------------------------------------------------------+ | VAX and AXP (in library dapdir:daphne.olb) | +----------------------------------------------------------------------+ | subroutine swab(numberOfWords,wordArray) | | | | Reverses low and high order bytes in an array of 16 bit words | | | | numberOfWords - input/integer*4 | | number of 16 bit words to process | | 0 implies "no operation" | | | | wordArray - input/output/integer*2 array | | the array to be processed | | must have at least word alignment | +----------------------------------------------------------------------+ Using Daphne with GammaSphere and GammaSphere Tapes Page 21 +----------------------------------------------------------------------+ | VAX and AXP (in library dapdir:daphne.olb) | +----------------------------------------------------------------------+ | subroutine swabQuadAligned(numberOfQuadWords,quadWordArray) | | | | Reverses low and high order bytes in an array of 64 bit words | | | | numberOfQuadWords - input/integer*4 | | number of 64 bit words to process | | 0 implies "no operation" | | | | quadWordArray - input/output/integer*8 array | | the array to be processed | | must be aligned to a quadword boundary | | i.e. an address which is a multiple of 8 | | | | AXP Fortran and C compilers will normally put all common blocks, | | and variables of length 8 at quadword (or higher) alignment. | | This includes integer*8, double precision, real*8, , complex*8 | | variables. It does NOT include character*8 variables which can | | be put on an arbitrary boundary. | +----------------------------------------------------------------------+ Character strings don't need to be byte swapped because they are stored the same way on both machines. Using Daphne with GammaSphere and GammaSphere Tapes Page 22 6 Excerpts From dapexe:gsStructures.inc +-------------------------------------------------------------------------+ | c | | c asciz fields: | | c C style ascii strings terminated by a zero byte. | | c The character strings in records received from GammaSphere or | | c read from tape are in asciz format. | | c Daphne routines convert them to Fortran style ascii strings by | | c removing the 0 and filling them with spaces to the end of the | | c allocated field. | | c | | structure /TAPE_HEADER/ | | integer*2 RecordType ! type=1 | | integer*2 RecordLength ! number of bytes this record (112.) | | integer*2 RecordVer ! record version or subtype | | integer*2 ByteOrder(2) ! to determine byte ordering | | character*40 exp_title1 ! first part of exp title (asciz) | | character*40 exp_title2 ! 2nd part of exp title (asciz) | | character*9 time ! hh:mm:ss (asciz) | | character*9 date ! yy/mm/dd (asciz) | | integer*2 TapeNum ! tape number (not used by gs) | | integer*2 TapeUnit ! specifies which unit wrote tape | | end structure | | | | structure /FILE_HEADER/ | | integer*2 RecordType ! type=2 | | integer*2 RecordLength ! number of bytes this record (90.) | | integer*2 RecordVer ! record version or subtype | | integer*2 RunNumber ! run number in this experiment | | integer*2 FileNumber ! file number in this experiment (?) | | character*40 run_title1 ! first part of run title (asciz) | | character*40 run_title2 ! 2nd part of run title (asciz) | | end structure | | | | structure /EVENT_BUFFER/ | | integer*2 RecordType ! type=3 | | integer*2 RecordLength ! bytes in this record (16384.) | | integer*2 RecordVer ! record version or subtype | | integer*2 HeaderBytes ! number of bytes in header | | integer*2 EffNumber ! eff processor number | | integer*2 StreamID ! event stream ID | | integer*2 EffSequence ! eff sequence number | | integer*2 ModeFlags ! event format flags | | integer*2 DateLength ! number of i*2 data words | | integer*2 CheckSumType ! 0=none 1=sum 2=crc16 | | integer*2 Checksum ! checksum value | | integer*2 EventData(EB_SIZE) ! event data area | | end structure | +-------------------------------------------------------------------------+ Using Daphne with GammaSphere and GammaSphere Tapes Page 23 7 Excerpts From dapexe:gsUnpack.inc +-------------------------------------------------------------------------+ | integer*4 maxSeg | | parameter (maxSeg=110) | | | | common /gs_event_segment_common/ ... | | integer*4 id(maxSeg) ! detector id | | integer*4 gebit(maxSeg) ! ge hit bit | | integer*4 bgohit(maxSeg) ! bgo hit pattern | | integer*4 ehi(maxSeg) ! high resolution ge energy | | logical*4 pu(maxSeg) ! pileup bit | | logical*4 over(maxSeg) ! overrange bit | | integer*4 tge(maxSeg) ! germanium time | | integer*4 tc(maxSeg) ! trap corrector | | integer*4 elo(maxSeg) ! low resolution ge energy | | integer*4 eside(maxSeg) ! side chan. energy for seg ge | | integer*4 tbgo(maxSeg) ! bgo time | | integer*4 ebgo(maxSeg) ! bgo energy | | | | common /gs_event_header_common/ ... | | integer*4 len_total ! total number of modules recorded | | integer*4 len_clean ! no of clean ge | | integer*4 len_dirty ! no of dirty ge | | integer*4 len_bgo ! no of bgo only | | integer*4 ttH ! usec-time high bits | | integer*4 ttM ! usec-time medium bits | | integer*4 ttL ! usec-time low bits | | integer*4 tac1 ! tac1 | | integer*4 tac2 ! tac2 | | integer*4 sumge ! ge summed energy | | integer*4 sumbgo ! bgo summed energy | | integer*4 extDetectorPos ! offset within event vector | | ! of external detector data (or 0) | | common /gs_ModeFlags_common/ ... | | integer*4 ModeFlags ! from EVENT_BUFFER | | logical*4 ModeFlags_bit0 ! bit 0 - not used | | logical*4 eff_gain_corr ! bit 1 - align all ge_high, | | ! ge _side energies | | ! (GE_GAIN_ADJUST) | | logical*4 eff_time_veto ! bit 2 - time gate | | ! (GE_TIME_GATE) | | logical*4 eff_adj_veto ! bit 3 - honeycomb suppres. done | | ! - see TL | | ! (BGO_HONEYCOMB) | | logical*4 wrt_ge_time ! bit 4 - ge_time | | logical*4 wrt_ge_full ! bit 5 - ge_time, ge_trap, ge_low | | logical*4 wrt_bgo_data ! bit 6 - bgo_time, bgo_low | | logical*4 wrt_all_ge ! bit 7 - dirty ge also (8 words) | | logical*4 wrt_bgo_det ! bit 8 - bgo w/o ge hits (8 words) | | logical*4 rf_timing ! bit 9 - do timing wrt RF tac in Eff | | logical*4 ModeFlags_bit10 ! bit 10 | | .... same for ModeFlags_bit11 through ModeFlags_bit11 | Using Daphne with GammaSphere and GammaSphere Tapes Page 24 | parameter (gsUnpack_badWC=1) | | parameter (gsUnpack_badLastWord=2) | | parameter (gsUnpack_exceedSane=3) | | parameter (gsUnpack_mismatch=4) | | parameter (gsUnpack_badExternal=5) | | parameter (gsUnpack_badID=6) | +-------------------------------------------------------------------------+