SATAN analysis
| GSI | Biophysics | SATAN long write-up |

SATAN Analysis programs


Let's consider a simple telescope experiment:

(Larger)

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.



Data Analysis with SATAN

The specific evaluation of an experiment (like data types, logical relations, spectra, and other derived quantities) is performed within analysis programs, which are linked to the SATAN system. The data structures initialized and filled this way are parts of SATAN data elements and may be accessed during a SATAN session interactively via system and user commands.

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 Programming Language

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:

More about macros you will find here.
All macro names begin with a '$' or a '@' (at-sign), and all system variable names contain a '_'. Therefore the user should not choose these characters for his own variable names.
Since the user and the SATAN system code share the same address space, the user section must be written carefully. Badly behaving user code might lead to corruption of the SATAN system code and thus produce unpredictable results.

The Structure of Analysis Procedures

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 beginning of an analysis (main) program is marked by a standard analysis program header, such as $GOOPROC for the evaluation of GOOSY list mode data in this example. To evaluate list mode data in EDAS format, only the header $GOOPROC must be replaced by $LISTPROC or $LISTVAR for events with fixed or variable length, respectively. Also the structure of analysis subroutines (header $ANLPROC) is identical. The end of an analysis program is indicated by the macro $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 */                                      

Three analyzers named 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.

Linearizations

We now describe a special analysis technique using the linearization data element. Note: unfortunately this feature is not yet implemented !
Assuming that the data element 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;

In this example 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.

Processing GOOSY/SBS/MBS data

The GOOSY raw data format ist different from the older EDAS format. The buffer size can be any power of 2 and the data contained therein are structured. Buffers and events have standard headers describing the data by type and subtype numbers. Moreover, data may have a byte order different from the native byte order of the machine SATAN is running on. These differences are handled as transparent as possible, that is, the analysis program always receives a complete event with the proper byte order. Because the events themselves may have a complex substructure some additional coding effort is necessary to access the various data objects within an event. In the following examples are shown how to analyse data of the most common types. At present data within an event must be accessed directly using pointers. In the future macros will be provided to facilitate this task.

GOOSY events of type 4, subtype 1

The event parameters come in uncompressed format, with zeroes included. They can directly be accumulated into spectra:
$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;


GOOSY events of type 4, subtype 2

The event parameters come in compressed format, with zeroes excluded. Each event parameter is accompanied by an ID identifying its position in an uncompressed event.
$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;


In this example the $EVENT macro contains just a dummy declaration of event parameters, the actual unpacking is done by directly accessing the members of the event structure of type 4 subtype 2.

GOOSY events of type 6, subtype 1 (Standard MBD Data)

These events have a complex structure the user has to deal with. They may consist of several subevents originating from different crates. The event parameters themselves come uncompressed.
$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;


In this example the $EVENT macro contains just a dummy declaration of event parameters, the actual unpacking is done by directly accessing the members of the event structure of type 6 subtype 1.

GOOSY events of type 10, subtype 1 (VME Data)


  
$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;
 

Aids to write analysis programs

Sorry, not yet available :-(
| GSI | Biophysics | SATAN long write-up |

Last updated: M.Kraemer@gsi.de, 13-Aug-2002