A scattered particle generates three signals which are digitized and form a set of correlated parameters (an event). These data can be saved on tape or disk and are fed into an analysis program which calculates derived quantities and performs a spectrum accumulation.
Usage and structure of SATAN commands are described in detail elsewhere. This chapter will introduce mainly into the usage of initialization and analysis procedures. Towards the end of this chapter a some examples will be given. They describe how to use available tools and utilities, and deal with questions often occurring when writing an analysis program.
The native language of SATAN is C.
This is also the language for analysis programs.
However, the most important standard functions for analysis procedures are
provided as
macros
which are expanded
by a special preprocessor into C code.
The shell command spp
(satan preprocessor)
is available for this purpose. The generated C code is then compiled
and linked with the SATAN system. All these steps (preprocessor+compile+link) are
supported with a single utility shell script
satmake
Once build, a user analysis is started together with SATAN:
satan <myanalysis>where
<myanalysis>
stands for the name of the user's
analysis executable.
The most important standard functions offered with macros and library functions are:
The macro concept has several advantages over explicit C coding:
The main purpose of an analysis program is to receive experimental list mode raw data in an event-by-event sequence. The user has to provide own code to perform all physics-related operations on the event parameter values (also called input values) of each single event, as for example window checking, numerical transformations, spectrum accumulation etc. The analysis routine is an external C function with embedded standard macros. Here is the skeleton of an analysis routine:
$GOOPROC; . ... definition part . $ANTRY; /* begin of analysis part */ $EVENT( event parameters ); . ... analysis . $ENDEVT; $ENDANL;
The definition part of the procedure contains definitions, initializations, and storage allocations of all items to be used. Here the (static) analyzers have to be created and the global parameters must be declared. This part is executed only once during the initial load of the SATAN system. The analysis part starts with the macro $ANTRY. This part is executed each time a block of event data (>=8 kbytes for GOOSY/MBS data, 4 kbytes for EDAS data) is ready for processing. Each block of event data consists of several events, which are handled event by event within a loop. This event loop is delimited by $EVENT and $ENDEVT. The following example shows a complete analysis routine for EDAS data:
$LISTPROC; $AGEN(AL) TYPE(2); $AGEN(BETA) LIMITS(0,2000) NCND(1); $AGEN(GAMMA) LIMITS(0,100); $ACDEF(BETA,1,150,600); $ANTRY; º/* End of Definition Part */ $EVENT(PATT,PA,PB,PC); º/* Event loop */ $ANAL(AL,PA); $ANAL(BETA,PB); if ( $AC(BETA,1) ) $ANAL(GAMMA,PC); $ENDEVT; º/* End of event loop */ $ENDANL; º/* End of analysis program */
AL
, BETA
, and GAMMA
are created, each
with the qualifier name LIST. AL
has the default
channel limits 1 to 1024. The analyzer type 2 means 2 bytes
integers. The analyzers will contain spectra and control
information. BETA
, for example, consists of a spectrum
running from channel number 0 to 2000, and has one condition,
namely number 1, which is set by the macro
$ACDEF
from 150 to 600.
Each event, which in this case consists of four parameters, is
processed in the loop from
$EVENT
to
$ENDEVT.
Variable names
are assigned to the event parameters (PATT, PA, PB, PC
in this
case) for subsequent reference in the program. For each event
in the loop all condition flags of all analyzers will be
cleared first.
Analyzer activity in the analysis part is invoked by the macro $ANAL with the analyzer name and event parameters (input values) as arguments. This macro first sets the analyzer's active flag. Then the input values are compared with the analyzer and condition limits. The corresponding flags (analyzer input valid bit and condition bits) are set. Finally the bin belonging to the input value (channel number) is incremented, thus accumulating the analyzer spectrum.
The macros
$AACT
and
$AC
are provided in order to check the
flags in subsequent program sections:
$AACT
checks the
active flag,
$AC
the specified condition flags. In this
example
$AC
is used to check the first condition flag of
analyzer BETA
whether it was set in the
$ANAL
macro in the
previous line. That means, if the input value PB
lies
inbetween the channels 150 and 600, then and only then
analyzer GAMMA
is incremented.
After reaching $ENDEVT the flow of control will be transferred again to the macro $EVENT , and the next event will be processed. This step is repeated as long as there are events in the buffer. $ENDANL in SATAN marks the end of processing of one data buffer, and control is returned to the calling SATAN system routine which will provide for the next buffer.
The following example shows a simplified evaluation of the telescope experiment. The analysis program consists of macros, interspersed with C, the language into which the macros will be expanded.
$LISTPROC; /* */ $PARDCL(R_EFAC, R_TFAC, R_DEFAC); float R_TZERO=0E0, R_EZERO=0E0, R_DEZERO=0E0, R_MCAL, R_Z2, R_ECAL, R_TCAL, R_DECAL; short ii; /* */ /* */ $AGEN (DENERGY) LIMITS(0,100) BINS(2) TYPE(2); $AGEN (ENERGY) LIMITS(0,100) BINS(2) TYPE(2); $AGEN (TIME) LIMITS(0,100) BINS(2) TYPE(2); $AGEN (MASSZ(3)) LIMITS(0,100,0,100) BINS(4) TYPE(2); $AGEN (CENERGY) LIMITS(0,3000) BINS(1) TYPE(24) NCND(3); /* */ $ACDEF(CENERGY,1,21,23); /* energy conditions */ $ACDEF(CENERGY,2,201,233); $ACDEF(CENERGY,3,2000,3000); /* */ /* */ $ANTRY; /* start of the analysis */ /* */ $EVENT(DE, T, E); $ANAL(DENERGY,DE); /* accumulate from the */ $ANAL(ENERGY,E); /* counters of the experiment */ $ANAL(TIME,T); /* */ R_ECAL=$GLOPAR(R_EFAC)*(E-R_EZERO); /* calibrate energy and energy loss */ R_DECAL=$GLOPAR(R_DEFAC)*(DE-R_DEZERO); $ANAL(CENERGY,R_ECAL); /* save calibrated energy */ R_TCAL=$GLOPAR(R_TFAC)*(T-R_TZERO); /* calibrate time */ /* */ R_MCAL=R_ECAL*R_TCAL*R_TCAL; /* evaluate the mass and */ R_Z2 = (R_ECAL/R_MCAL) *R_DECAL*$GLOPAR(R_EFAC);/* square of the charge */ /* */ for ( ii=0; ii<=3; ii++ ) { if ( $AC(CENERGY,ii) ) /* for three energies accumulate */ $ANAL(MASSZ(ii),R_MCAL,R_Z2); /* mass and charge */ } /* */ $ENDEVT; /* end of event loop */ $ENDANL; /* end of analysis */
The macros for th header and the generation of analyzers are the same as in the previous example.
Three parameters are processed with the
$EVENT
macro: DE
(for
energy loss), T
(for time of flight) and
E
(for energy).
These raw data are analyzed in the analyzers
DENERGY
, ENERGY
,
and TIME
. Now derived quantities (the calibrated data) are
calculated. The calibrated energy is fed into the analyzer
CENERGY
and as a result of some condition flag checking the
analyzers MASSZ(i)
are accumulated: mass and the square of
the charge are kept for three different energy ranges.
The example also shows a flexible way to set calibration factors interactively by declaring them as global parameters with the macro $PARDCL. They are known within the analysis program as well as in the interactive part of SATAN. They can be set and modified interactively by the command IPAR at any time during the SATAN session. Due to their special implementation they must be accessed with the macro $GLOPAR().
Global parameters may have various data types and may also be arrays:
$PARDCL(CTEXT) TYPE(80) INIT('Meine Messung:'); $PARDCL(BFLAGS(12)) TYPE(0); $PARDCL(DVAL,DERR) TYPE(4);A characterstring, an array of 12 booleans and two double precision floating point global variables are declared.
linear.lin
has been fetched from a data element
library before, an example looks like the following
$LISTPROC; ... int iRC; short I_ENERGY,I_ENERGY_LOSS; float R_CHARGE; ... $AGEN (ENERGY) LIMITS(1,1024) TYPE(24); $AGEN (ENERGY_LOSS) LIMITS(1,1024) TYPE(24); $AGEN (CHARGE) LIMITS(1,1024) TYPE(24); $ANTRY; $EVENT(I_ENERGY,I_TIME); ... $ANAL(ENERGY,I_ENERGY) ; $ANAL(ENERGY_LOSS,I_ENERGY_LOSS) ; ... $LFETCH($LINEAR); R_CHARGE = $LINEAR("LINEAR","LIN", (float) I_ENERGY), (float) I_ENERGY_LOSS, &iRC); $ANAL(CHARGE, (floor) (R_CHARGE*100) ); ... $ENDEVT; $ENDANL;
I_ENERGY
and I_ENERGY_LOSS
will be rearranged according to the linearization prescription
linear.lin
.
The result will be returned in R_CHARGE
and histogrammed
in analyzer CHARGE
with a stretch factor of 100 for better
resolution.
$GOOPROC; $AGEN(DLEN) LIMITS(1,1024); /* DATA LENGTH */ $AGEN(TYPE); /* TYPE */ $AGEN(SUBTYPE); /* SUBTYPE */ $AGEN(PARAM(50)) limits(1,8192); /* EVENT PARAMETER */ struct SIOGOOSYEVT41 *psE41; int ii,nn; $ANTRY; $EVENT(EVT_PARM(50)); /* 50 PARAMETERs (2 bytes) PER EVENT */ /* event address */ psE41 = (struct SIOGOOSYEVT41 *) p_pars; /* */ $ANAL(DLEN,psE41->sBEH.lDLen); /* DATA LENGTH */ $ANAL(TYPE,psE41->sBEH.iType); /* EVENT TYPE */ $ANAL(SUBTYPE,psE41->sBEH.iSubType); /* EVENT SUBTYPE */ /* sort event parameters into spectra*/ nn = psE41->sBEH.lDLen; /* # of event parameters */ nn = min(nn,50); for( ii=1; ii<=nn; ii++ ) { $ANAL( PARAM(ii), $EVTPAR(EVT_PARM(ii)) ); } $ENDEVT; $ENDANL;
$GOOPROC; $AGEN(DLEN) LIMITS(1,1024); /* DATA LENGTH */ $AGEN(TYPE); /* TYPE */ $AGEN(SUBTYPE); /* SUBTYPE */ $AGEN(PARAM(50)) limits(1,8192); /* EVENT PARAMETER */ struct SIOGOOSYEVT42 *psE42; struct SIOGOOSYEVT42DATA *psE42D; int ii,nn, iID, iData; $ANTRY; $EVENT(EVT_PARM(100)); /* 50 PARAMETERs (2 bytes) PER EVENT */ /* event address */ psE42 = (struct SIOGOOSYEVT42 *) p_pars; /* */ $ANAL(DLEN,psE42->sBEH.lDLen); /* DATA LENGTH */ $ANAL(TYPE,psE42->sBEH.iType); /* EVENT TYPE */ $ANAL(SUBTYPE,psE42->sBEH.iSubType); /* EVENT SUBTYPE */ /* sort event parameters into spectra*/ nn = psE42->sBEH.lDLen/2; /* # of event parameters */ nn = min(nn,50); psE42D = (struct SIOGOOSYEVT42DATA *) ( &(psE42->sBEH) + 1 ); for( ii=1; ii<=nn; ii++ ) { iID = psE42D -> iID; iData = psE42D -> iData; if ( ( iID > 0 ) && ( iID <= 50 ) ) { $ANAL( PARAM(iID), iData ); } psE42D++; } $ENDEVT; $ENDANL;
$GOOPROC; $AGEN(DLEN) LIMITS(1,1024); /* DATA LENGTH */ $AGEN(TYPE); /* TYPE */ $AGEN(SUBTYPE); /* SUBTYPE */ $AGEN(subevtlen); /* */ $AGEN(crate); /* */ $AGEN(counter); /* */ $AGEN(PARAM(10)) limits(1,8192); /* EVENT PARAMETER */ struct SIOGOOSYEVT6 *psE6; struct SIOGOOSYEVT6SUB *psE6S; short *pi; int ii,nn; $ANTRY; $EVENT(EVT_PARM(50)); /* 50 PARAMETERs (2 bytes) PER EVENT */ /* event address */ psE6 = (struct SIOGOOSYEVT6 *) p_pars; /* */ $ANAL(DLEN,psE6->sBEH.lDLen); /* DATA LENGTH */ $ANAL(TYPE,psE6->sBEH.iType); /* EVENT TYPE */ $ANAL(SUBTYPE,psE6->sBEH.iSubType); /* EVENT SUBTYPE */ /* sort event parameters into spectra*/ nn = psE6->sBEH.lDLen; /* # of event parameters */ psE6S = (struct SIOGOOSYEVT6SUB *) ( &( psE6 -> sBEH ) + 1); while ( nn > 0 ) { $ANAL( subevtlen, psE6S->iSubEvtLen ); $ANAL( crate, psE6S->ucCrate ); $ANAL( counter, psE6S->ucCounter ); pi = (short *) (psE6S + 1); for ( ii=0; ii<nn; ii++ ) { if ( ii < 10 ) { $ANAL( PARAM(ii+1), *pi ); } pi++; } nn -= psE6S->iSubEvtLen * 2 + sizeof(*psE6S); psE6S = (struct SIOGOOSYEVT6SUB *) ( (short *) (psE6S+1) + psE6S->iSubEvtLen ); } $ENDEVT; $ENDANL;
$GOOPROC; /*----------------------------------------------------------------*/ /* GOOSY RAW DATA INPUT */ /* TEST PROGRAM FOR BUFFER TYPE 10,1 (UNPACKED EVENTS) */ /*----------------------------------------------------------------*/ $AGEN(DLEN); $AGEN(TYPE); $AGEN(SUBTYPE); $AGEN(TRIGGER); $AGEN(COUNTER) TYPE(4) LIMITS(0,32765); $AGEN(LWORDS) TYPE(4) LIMITS(1,1024); $AGEN(DATA(1,10)) TYPE(4) LIMITS(1,8192); struct SIOGOOSYEVT10 *psE10; struct SIOGOOSYEVT101SUB *psE101S; struct SIOGOOSYEVT101DATA *psE101D; $ANTRY; $EVENT( p(8192) ); { short iSubEvent, ii; long lDLen=0, lDLenSub = 0; int iPar, nPar; /* event address */ psE10 = (struct SIOGOOSYEVT10 *) p_pars; /* */ $ANAL( dlen, psE10 -> sBEH.lDLen ); $ANAL( type, psE10 -> sBEH.iType ); $ANAL( subtype, psE10 -> sBEH.iSubType ); $ANAL( trigger, psE10 -> iTrigger ); $ANAL( counter, psE10 -> lCount ); /* subevent address */ psE101S = (struct SIOGOOSYEVT101SUB *) (psE10+1); /* event length */ lDLen = psE10 -> sBEH.lDLen; if ( lDLen > 0 ) { psE101D = (struct SIOGOOSYEVT101DATA *) (psE101S+1); lDLenSub = psE101S -> sBEH.lDLen; nPar = lDLenSub - ( sizeof(struct SIOGOOSYEVT101SUB) - sizeof(struct SIOGOOSYBEH ) ) / 2; nPar /= 2; /* # of data long words */ $ANAL( lwords, nPar ); for ( iPar=0; iPar < nPar; iPar++ ) { if ( ( psE101D -> iID > 0 ) && ( psE101D -> iID <= 10 ) ) $ANAL( data(1, psE101D->iID ), psE101D->iValue ); psE101D++; } } } $ENDEVT; $ENDLIST;
Last updated: M.Kraemer@gsi.de, 13-Aug-2002