DAQ running on Sun Unix
(January 2003)

Index:

  1. Short description
  2. Hardware
  3. Software
  4. Main Directory
  5. Gasp User Directory Structure
  6. Sample NEO++ Online Program
  7. The event_param.h file
  8. The ADC_Neo.inc file
  9. A Spy Sample Program
  10. Other Useful Directories
  11. OCP
  12. XmSpecview
  13. XmMatview
Short Description: The new GASP Data Acquisition System (DAQ)is based on the same old Camac FERA ADC/TDC conversion system read out by a more modern VME R.U. Unit and a Sun Workstation implementing a revised version of the EUROBALL (EB) Data Acquisition Software running under Unix operating System..
The Hardware of the New DAQ consists on 3 main parts:
  1. The Camac ADC/TDC conversion system.
  2. The VME Based Readout Unit (RU) collectiong Event fragments.
  3. A Sun Enterprise 450 Server with 4 processors UltraSpark II 296 MHz, running Unix and managing one DLT 7000, one DLT4000 and 2 Exabyte 8500 tape units for data storage.
The data path from ADC to Tape uses:
The standard Fera Drivers for data readout from the Phoenix (home made units adapting Camberra ADC 8715 converters for the Germanium detectors) and the Silena ADC/TDC/QDC for all the other event parameters.
A Fera Funnel Unit allowing the high speed sequential readout of the event fragments from up to 4 Fera buses and the direct connection with a VME readout unit. The data after consistent derandomization is sent via TCP/IP (100Mb) to the Sun WS where a BU.exe program allows the building up the final Event.
Before sending the event to the Neo++ program a dedicated code:
  1. checks the event self-consistency and records formatting errors,
  2. translates the event parameters from the Hardware codes to the software names. (see the event_param.h file)
The Event is then read by a User designed Neo++ program that is responsible of further checking of the event, building the needed spectra, filtering and saving the events in the Tape mass storage. The Neo++ program mantains the BU link closed until the event has been fully processed.
In order to reduce de bottleneck produced by a heavy CPU load of the Neo++ code, two types of Neo++ programs are used.
  1. The online code(needed) processing the 100% of the events. The data acquisition speed depends on the efficiency of this code.
  2. The spy code (optional), processing only the fraction of the events permitted by the available CPU power and data handling complexity.
In the ONLINE program the processing is reduced to a minimum, event classification, spectra reflecting the statistics of the relevant detector, spectra histogramming the critical parameters are produced and the good events are sent to Tapes and to the following SPY Neo++ program. Usually 3 instances of the online program are running loading 3 out of the 4 available processors. In order to check the CPU load, type the Unix top command in a dedicated shell window. Stop top using CRTL C.
In the SPY program, more sophisticated processing is performed, for the Germanium data, parameter calibration, gain adjustment and doppler corrections can be applied, detector summing of corrected data can be performed, spectra, 2D matrices, gated and banana selected data can be organized following the specific ueser needs. The SPY code uses the remaining processor. The number of running instances must be calibrated avoiding to load more then one CPU.
The CORBA based Unix Software has been developped by the LNL Computer Service Team (Ref).
The complex software takes care of many different tasks. Full task control/sincronization is achieved using CORBA.
The main parts of this software are:
  • the RUN Control Program OCP. The program allows operating control of the following programs.
  • the RU&BU control tasks. RU is the Readout process, BU is the Event Builder process.(1, only Control)
  • the Tape Manager (control of the 4 Tape Servers) (2, Check, launch,Control)
  • the NEO++ Online and Spy programs (each one can have several instances running concurrently)(3, launch)
  • the Histogram Manager (control of the 4 Histograms Servers)(4, check,launch,erase,delete)
  • the Histogram Bridge, an external world access gate, via Rpc procedures, to the produced Histograms,
  • the histogram viewer XmSpecview.(5, launch)
  • the 2D matrix viewer XmMatview.(6,launch)
  • the Camac Control procedures for ADC programming and Trigger Start and Stop.(7,IEEE488)

Main directory:
gaspux4:/Gasp_Programs/bin

Content: General purpose Acq. Programs. Go to Index

Gasp_User Directory Structure
gaspux4:/Gasp_Users/Config

Content: Set of Folders with the current and the archived NEO++ programs and related
information.

gaspux4:/Gasp_Users/Config/current

Content: A Single Folder with the CURRENT Experiment set of NEO programs and related
information.

Inside every directory, Files with extension :

.cc are source code NEO++ programs.
.h are header files of NEO++ programs.
.o are compiled NEO++ programs.
.mk are make files.

gaspux4:/Gasp_Users/Config/archive

Content: Set of Folders, one for each experiment, containenig the NEO++ programs and related information

gaspux:/Gasp_Users/Config/current/Your_Exp/display

Content: Set of Folders (one for each experiment and/or
research group) with spectrum DISPLAY layout files.

online_name
Content: On-line XmSpecview display file information. The files are those defined in the online NEO++ programs

spy_name
Content: Analysis XmSpecview display file information. The files are those defined in the ANALYSIS NEO++ programs, Go to Index

Sample NEO++ Online Program:
We will assume that the current experiment name is gasp_std
The online program name will be gasp_std.cc,
It will be located in the directory:
 gaspux:/Gasp_Users/Config/current/gasp_std/online
the related spy a_gasp_std.cc will be located in the directory:
 gaspux:/Gasp_Users/Config/current/gasp_std/analysis
both programs will include the same event_param.h file describing the event parameters.
The event_param.h file MUST match the ADC_Neo.inc file located in
 gaspux:/Gasp_Users/Config/current/gasp_std/camac
and used to configure the CAMAC ADC cards.



In the following code explanations are blue coloured.
// Gasp standard online program
// The Event is formed by:
//    1 BGO Detector with
//       BGO sum energy and multiplicity
//       Ge sum energy and multiplicity
//    40 Ge detector with
//      Ge energy and time information

#include "/euroball/src/neo/include/neo++.h"   -> main include file

#include "event_params.h"                   -> 
Event parameter file
                                         -> (must be located in the same directory)

                                               -> Any GLOBAL variable can be defined here.
int   do_invalidate = 0;                    -> Invalidate detector Flag
int   do_errors = 0;
void  toggle_invalidate(int);

void  toggle_invalidate(int signal)    
{
  do_invalidate = ! do_invalidate;            -> toggle invalidate flag
  if(do_invalidate) {                         -> Invalidate Germanium if the one parameter is missing
    printf("Invalidate Enabled !!\n");
  }else{
    printf("Invalidate Disabled !!\n");
    
  }
  if(do_invalidate) {
    do_errors = 0;
  }else {
    do_errors = 1;                            -> perform histogramming also if event in error
  }
}

int    do_write_tape = 0;                    -> Write Tape Flag
void   toggle_tape(int);

void    toggle_tape(int signal)
{
  do_write_tape = ! do_write_tape;
  if(do_write_tape) {
    printf("Tape Write Enabled !!\n");
  }else{
    printf("Tape Write Disabled !!\n");
    
  }
}

//////////
// main //
//////////


eb_main {                                      -> Main online Code

  if(sigset(SIGUSR1, toggle_invalidate) == SIG_ERR) {  -> Enable First User Signal (Invalidate Detector)
    printf(" Error setting SIGUSR1\n");
  }
  if(sigset(SIGUSR2, toggle_tape) == SIG_ERR) {       -> Enable Second User Signal (write tape)
                                                -> (only 2 signals are available)
    printf(" Error setting SIGUSR2\n");
  }
  Event event;                                     -> event type RAW and online (standard) 
                                                -> see even request  and event use
  event.setVerboseOff();

   Tape tape (2, 32768);                       -> tape (Stream 2,32K block size)
                                         -> see below tape use



  Spy spy(1,1.0,32768);                        -> spy (channel 1, maximum data rate, 32K Block size)
                                         -> see below local use and 
   how to use it in the spy program


                                               -> Note that Histograms can be defined only INSIDE the Main code.


  Hist1D          ev_class(512,"ev_class");

  Hist1D          ge_stat(512,"ge_stat");
  Hist1D          tot_stat(512,"tot_stat");
  
  Hist1D          Bgo_Mult(4096,"bgo_mult");
  Hist1D          Bgo_Esum(4096,"bgo_esum");
  Hist1D          Ger_Mult(4096,"ger_mult");
  Hist1D          Ger_Esum(4096,"ger_esum");

  VectHist1D<40>  Ge_Ener(8192,"ge_ener");
  VectHist1D<40>  Ge_Time(4096,"ge_time");

  int  startCh=1,npar,detPos,countPar,invalidate;
  int   detKey,flush,evnum;
  int   howManyB, howManyG;
  
  evnum=flush=0;

// Note that the while loop is internal to the try/catch loop

  try {
    while(1) {                             -> Loop forever and catch errors
      event.next();                   -> Ask for the Next Event
      ev_class.inc(60);                 -> Count events by Incrementing spectrum "ev_class" 
                                     -> at channel 60
      if(flush++ == 3000) {              -> Flush after 3000 events
        cout << "Online Flush After  : " << evnum << " events." <<endl;
        base_histo::flush();
        flush=0;
      }

      int ErrorSum = 0;
      if(event.isBad()) {              -> event error reporting
        for(int kk=0;kk<event.classification.size();kk++) {
            if(event.classification[kk]){  -> event error type
            ErrorSum += kk;
            ev_class.inc(kk);
          }
        }
      }              
                                      -> Handle event ONLY if 

      if(do_errors && (ErrorSum != 0) || (!do_errors && (ErrorSum == 0 || ErrorSum == 10))) {
        if(do_write_tape)                -> If Flag allows
        if(do_write_tape)
            tape << event;               -> send event to Tape
        ev_class.inc(61);
        tot_stat.inc(61);
// BGO statistics        
            howManyB= B.howManyFired();      // BGO ball Total Energy and Multiplicity
            if(howManyB == 1) {
          invalidate = npar = 0;
          if(B(0).bgo_count > startCh) {      // Good parameter BK
                Bgo_Mult.inc(B(0).bgo_count);
            tot_stat.inc(70);
            npar++;
          }
          if(B(0).bgo_ener > startCh) {        // Good parameter BE
                Bgo_Esum.inc(B(0).bgo_ener);
            tot_stat.inc(71);
            npar++;
          }
          if(npar == 2) {                     // Good all Params B K&E
            tot_stat.inc(73);
          }
          npar = 0;
          if(B(0).ger_count > startCh) {      // Good parameter GK
                Ger_Mult.inc(B(0).ger_count);
            tot_stat.inc(75);
            npar++;
          }
          if(B(0).ger_ener > startCh) {        // Good parameter GE
                Ger_Esum.inc(B(0).ger_ener);
            tot_stat.inc(76);
            npar++;
          }
          if(npar == 2) {              // Good all Params G K&E
            tot_stat.inc(77);
            }
        }
// Ge statistics        
        howManyG = G.howManyFired();    // Ge Detectors E,T for each detector firing
        tot_stat.inc(400 + howManyG);
        ge_stat.inc(400 + howManyG);

        if(howManyG) {
          tot_stat.inc(62);
          countPar = 0;
            for( int jg=0; jg < G.howManyFired(); jg++ ) {
            npar = 0;
              detKey = G(jg).keyGet();
            detPos = 10*detKey;
            if(G(jg).ener > startCh) {      // Good parameter E
              npar++;
                  Ge_Ener[detKey].inc(G(jg).ener);
              ge_stat.inc(detPos);
            }
            detPos++;
            if(G(jg).time > startCh) {      // Good parameter T
              npar++;
                Ge_Time[detKey].inc(G(jg).time);
              ge_stat.inc(detPos);
            }
            detPos++;
            if(npar == 2) {            // Good both Params E,T
              ge_stat.inc(detPos);
              tot_stat.inc(detKey);
              countPar++;
            }else{            // Both Energy and Time are missing
              if(do_invalidate && invalidate == 2)  -> If detector not complete
                G(jg).invalidate();               -> Invalidate detector jg
            }
          }
          if(countPar)
            tot_stat.inc(40+countPar);
          howManyG = G.howManyFired();
          ge_stat.inc(420 + howManyG);
        }


          spy  << event;                         -> Send Event to Spy a_gasp_std
        evnum++;
      }
    }
  }catch (RWxmsg & x) { cerr<<x.why()<<endl; }  // catch errors
}

Go to Index
The event_param.h header file describes the event parameters.
It MUST match the information contained in the CAMAC file ADC_Neo.inc located in the
gaspux4:/Gasp_Users/temp/Calibration/current/gasp_std/camac
directory.

Code of
event_param.h
/* Event format descriptor */


/* BGO Ball detector */

format (BGO_BALL)           -> BGO ball format
     item   bgo_ener;
     item   bgo_count;
     item   ger_ener;
     item   ger_count;
end_format
Detector<BGO_BALL, FERA_0> B;

/* Ge detector */
format (GASP_ARRAY)         -> Germanium format
     item   ener;
     item   time;
end_format
Detector<GASP_ARRAY, FERA_1> G;
                            -> Germanium detectors use Phoenix type ADC with
converter(phoenix, 0)     -> VSN (Virtual Station Number) 0
  entry ( 0 , G[ 0].ener),  -> Energy of detector 0 (zero) is in ADC channel 0
  entry ( 1 , G[ 1].ener),
  entry ( 2 , G[ 2].ener),
  entry ( 3 , G[ 3].ener),
  entry ( 4 , G[ 4].ener),
  entry ( 5 , G[ 5].ener),
  entry ( 6 , G[ 6].ener),
  entry ( 7 , G[ 7].ener),
  entry ( 8 , G[ 8].ener),
  entry ( 9 , G[ 9].ener),
  entry (10 , G[10].ener),
  entry (11 , G[11].ener),
  entry (12 , G[12].ener),
  entry (13 , G[13].ener),
  entry (14 , G[14].ener),
  entry (15 , G[15].ener)   -> Energy of detector 15 is in ADC channel 15
end_converter

converter(phoenix, 1)       -> VSN (Virtual Station Number) 1
  entry (0 , G[16].ener),   -> Energy of detector 16 is in ADC channel 0
  entry (1 , G[17].ener),
  entry (2 , G[18].ener),
  entry (3 , G[19].ener),
  entry (4 , G[20].ener),
  entry (5 , G[21].ener),
  entry (6 , G[22].ener),
  entry (7 , G[23].ener)    -> Energy of detector 23 is in ADC channel 7
end_converter

converter(phoenix, 2)       -> VSN (Virtual Station Number) 2
  entry ( 0 , G[24].ener),  -> Energy of detector 24 is in ADC channel 0
  entry ( 1 , G[25].ener),
  entry ( 2 , G[26].ener),
  entry ( 3 , G[27].ener),
  entry ( 4 , G[28].ener),
  entry ( 5 , G[29].ener),
  entry ( 6 , G[30].ener),
  entry ( 7 , G[31].ener),
  entry ( 8 , G[32].ener),
  entry ( 9 , G[33].ener),
  entry (10 , G[34].ener),
  entry (11 , G[35].ener),
  entry (12 , G[36].ener),
  entry (13 , G[37].ener),
  entry (14 , G[38].ener),
  entry (15 , G[39].ener)    -> Energy of detector 39 is in ADC channel 15
end_converter
                             -> BGO parameter use Silena type ADC  with
converter(silena,3)        -> VSN (Virtual Station Number) 3
  entry(0,B[0].bgo_ener),    -> BGO Total Energy in channel 0
  entry(1,B[0].bgo_count)    -> BGO Multiplicity in channel 1
end_converter

converter(silena,4)          -> Ge Total Energy&Mult use Silena type ADC with VSN (Virtual Station Number) 4
  entry(0,B[0].ger_ener),    -> Ge Total Energy in channel 0
  entry(1,B[0].ger_count)    -> Ge Multiplicity in channel 1
end_converter

                       -> Germanium detectors use Silena type TDC with
converter(silena,5)       -> VSN (Virtual Station Number) 5
  entry(0,G[7].time),       -> Time of detector 7 is in ADC channel 0
  entry(1,G[6].time),       -> Note the Connection Inversion !!
  entry(2,G[5].time),
  entry(3,G[4].time),
  entry(4,G[3].time),
  entry(5,G[2].time),
  entry(6,G[1].time),
  entry(7,G[0].time)        -> Time of detector 0 is in ADC channel 7
end_converter
                       -> Germanium detectors use Silena type TDC with
converter(silena,6)       -> VSN (Virtual Station Number) 6
  entry(0,G[15].time),
  entry(1,G[14].time),
  entry(2,G[13].time),
  entry(3,G[12].time),
  entry(4,G[11].time),
  entry(5,G[10].time),
  entry(6,G[ 9].time),
  entry(7,G[ 8].time)
end_converter
                       -> Germanium detectors use Silena type TDC with 
converter(silena,7)       -> VSN (Virtual Station Number) 7
  entry(0,G[23].time),
  entry(1,G[22].time),
  entry(2,G[21].time),
  entry(3,G[20].time),
  entry(4,G[19].time),
  entry(5,G[18].time),
  entry(6,G[17].time),
  entry(7,G[16].time)
end_converter
                       -> Germanium detectors use Silena type TDC
converter(silena,8)        -> VSN (Virtual Station Number)  8
  entry(0,G[31].time),
  entry(1,G[30].time),
  entry(2,G[29].time),
  entry(3,G[28].time),
  entry(4,G[27].time),
  entry(5,G[26].time),
  entry(6,G[25].time),
  entry(7,G[24].time)
end_converter
                      -> Germanium detectors use Silena type TDC
converter(silena,9)       -> VSN (Virtual Station Number)  9
  entry(0,G[39].time),
  entry(1,G[38].time),
  entry(2,G[37].time),
  entry(3,G[36].time),
  entry(4,G[35].time),
  entry(5,G[34].time),
  entry(6,G[33].time),
  entry(7,G[32].time)
end_converter


Go to Index
The ADC_Neo.inc header file describes the CAMAC event parameters.
It MUST match the information contained in the event_param.h file in the
gaspux4:/Gasp_Users/temp/Calibration/current/gasp_std/online
directory.

Content of ADC_Neo.inc
CRATE 1
SLOT 25 type Controller
zci

SLOT 3 type Phoenix    -> SLOT in Crate and card Type
setvsn 0             -> VSN (Virtual Station Number) 0 see file event_param.h
conf_module 7
conf_adc 2
routing_mask 0
cc_width 25
cc_delay 5
busy-dr_delay 65
le-dr_delay 5
so_width 2
da_width 2

SLOT 4 type Phoenix
setvsn 1               -> VSN (Virtual Station Number) 1
conf_module 7
conf_adc 2
routing_mask 0
cc_width 25
cc_delay 5
busy-dr_delay 65
le-dr_delay 5
so_width 2
da_width 2

SLOT 5 type Phoenix
setvsn 2             -> VSN (Virtual Station Number) 2
conf_module 7
conf_adc 2
routing_mask 0
cc_width 25
cc_delay 5
busy-dr_delay 65
le-dr_delay 5
so_width 2
da_width 2

SLOT 13 type SilenaV
clear
setvsn 3             -> VSN (Virtual Station Number) 3
common 10
SUBCHANNEL 0-7
offset 100 lld 20 uld 127

SLOT 14 type SilenaV
clear
setvsn 4              -> VSN (Virtual Station Number) 4
common 10
SUBCHANNEL 0-7
offset 100 lld 20 uld 127

SLOT 15 type SilenaT
clear
setvsn 5             -> VSN (Virtual Station Number) 5
SUBCHANNEL 0-7
offset 128 lld 20 uld 127

SLOT 16 type SilenaT
clear
setvsn 6
SUBCHANNEL 0-7
offset 128 lld 20 uld 127

SLOT 17 type SilenaT
clear
setvsn 7
SUBCHANNEL 0-7
offset 128 lld 20 uld 127

SLOT 18 type SilenaT
clear
setvsn 8
SUBCHANNEL 0-7
offset 128 lld 20 uld 127

SLOT 19 type SilenaT
clear
setvsn 9
SUBCHANNEL 0-7
offset 128 lld 20 uld 127
Go to Index


The a_gasp_std.cc file is the spy partner of the gasp_std.cc code.
It MUST make reference to the SAME event_param.h file located in the
gaspux4:/Gasp_Users/temp/Calibration/current/gasp_std/online
directory.

Content of a_gasp_std.cc
// Standard GASP Spy version

#include "/euroball/src/neo/include/neo++.h"

#include "../../online/event_params.h"

//////////
// main //
//////////

void        enable_read(int);
void        enable_other(int);
int          read_file(void);
int         read_calib(int);
int         read_shift(int);
int         read_banana(int);

float        ge_egain,recoil_vc;
float        ge_ecal[40][4],ge_tshift[40];


VectLocGate<4>    Ge_Ener_Gate(4096);    // Ge Gates
LocGate        Ge_Time_Gate(4096);
int           howManySets = 0;
int          low,high;

LocBanana      BGO_Ban(256,256);  // BGO Banana
  
int          do_read_file = 0;

void  enable_read(int signal)
{
  do_read_file = 1;
  printf("Read File at Next event !!\n");
}

void  enable_other(int signal)
{
  exit(0);
}

eb_main {
  if(sigset(SIGUSR1, enable_read) == SIG_ERR) {
    printf(" Error setting SIGUSR1\n");
  }
  if(sigset(SIGUSR2, enable_other) == SIG_ERR) {
    printf(" Error setting SIGUSR2\n");
  }
    Event event(FORMATTED,Spy(1,32768));    ->event type FORMATTED and spy on channel 1 
                                         ->(see spy def or spy use in  gasp_std.cc )
  event.setVerboseOff();

  Hist1D             classif(256,"a_stat_tot");

  Hist1D        Bgo_Mult(4096,"a_bgo_count");
  Hist1D         Bgo_Esum(4096,"a_bgo_ener");
  Hist2D         Mat_Bgo(256,256,"mat_bgo");
  Hist2D         Mat_Bgo_Ban(256,256,"mat_bgo_ban");
  Hist1D        Ger_Mult(4096,"a_ger_count");
  Hist1D         Ger_Esum(4096,"a_ger_ener");

  VectHist1D<40>    Ge_Ener(4096,"a_ge_ener");
  VectHist1D<40>    Ge_Time(4096,"a_ge_time");
  VectHist1D<7>    Ge_Rings(4096,"a_ge_rings");
  
  Hist1D        Ge_E_All(4096,"a_ge_ener_all");
  Hist1D        Ge_T_All(4096,"a_ge_time_all");
  
  VectHist1D<4>    Ge_E_Gate(4096,"a_ge_ener_gate");
  VectHist1D<4>    Ge_E_SGated(4096,"a_ge_gated1");
  VectHist1D<4>    Ge_E_DGated(4096,"a_ge_gated2");
  Hist1D        Ge_T_Gate(4096,"a_ge_time_gate");
  
  Hist1D        BGO_K_Gate(4096,"a_bgo_mult_ban");
  Hist1D        BGO_H_Gate(4096,"a_bgo_ener_ban");
  Hist1D        Ge_BGO_Gated(4096,"a_ge_bgo");
  
  
  int          howManyB, howManyG;
  int          rnd_step,rnd_mod,rnd_val;
  float        rnd_rnd,rnd_num;
  float        doppler[40],costheta[40];
  int          ring[40];
  float        rtmp,geval;
  long        kbval,hbval;
  long        tval,gtval;
  int         i,j,k,m,detKey,npar;
  int          ii,jj,kk;

// Initialisations
  rnd_step   = 359;      // random number increment
  rnd_val    = rnd_step;    // initial value
    rnd_mod    = 1024;         // "random" number modulo.
    rnd_rnd    = 1./1024.;     // 1/rnd_mod..

  for (i=0;i<40;i++) {      // Perform Ge Calibration                     
      for (j=0;j<4;j++)
        ge_ecal[i][j]  = 0.0;  
      ge_ecal[i][1]    = 1.0;  
      ge_tshift[i]    = 0;  
      doppler[i]      = 1.0;  
  }
  ge_egain        = 2.0;
    
  recoil_vc        = 0.0;

  costheta[ 0]  =  0.80902;
  costheta[ 1]  =  0.80902;
  costheta[ 2]  =  0.85065;
  costheta[ 3]  =  0.85065;
  costheta[ 4]  =  0.80902;
  costheta[ 5]  =  0.80902;
  costheta[ 6]  =  0.50000;
  costheta[ 7]  =  0.50000;
  costheta[ 8]  =  0.50000;
  costheta[ 9]  =  0.50000;
  costheta[10]  =  0.52573;
  costheta[11]  =  0.52573;
  costheta[12]  =  0.30902;
  costheta[13]  =  0.30902;
  costheta[14]  =  0.30902;
  costheta[15]  =  0.30902;
  costheta[16]  =  0.00000;
  costheta[17]  =  0.00000;
  costheta[18]  =  0.00000;
  costheta[19]  =  0.00000;
  costheta[20]  =  0.00000;
  costheta[21]  =  0.00000;
  costheta[22]  =  0.00000;
  costheta[23]  =  0.00000;
  costheta[24]  = -0.30902;
  costheta[25]  = -0.30902;
  costheta[26]  = -0.30902;
  costheta[27]  = -0.30902;
  costheta[28]  = -0.50000;
  costheta[29]  = -0.50000;
  costheta[30]  = -0.50000;
  costheta[31]  = -0.50000;
  costheta[32]  = -0.52573;
  costheta[33]  = -0.52573;
  costheta[34]  = -0.80902;
  costheta[35]  = -0.80902;
  costheta[36]  = -0.85065;
  costheta[37]  = -0.85065;
  costheta[38]  = -0.80902;
  costheta[39]  = -0.80902;

  ring[0]  = 0;            // 30 degrees
  ring[1]  = 0;      
  ring[2]  = 0;
  ring[3]  = 0;
  ring[4]  = 0;
  ring[5]  = 0;
  ring[6]  = 1;      // 60 degrees
  ring[7]  = 1;
  ring[8]  = 1;
  ring[9]  = 1;
  ring[10] = 1;
  ring[11] = 1;
  ring[12] = 2;      // 72 degrees
  ring[13] = 2;
  ring[14] = 2;
  ring[15] = 2;
  ring[16] = 3;      // 90 degrees
  ring[17] = 3;
  ring[18] = 3;
  ring[19] = 3;
  ring[20] = 3;
  ring[21] = 3;
  ring[22] = 3;
  ring[23] = 3;
  ring[24] = 4;      // 108 degrees
  ring[25] = 4;
  ring[26] = 4;
  ring[27] = 4;
  ring[28] = 5;      // 120 degrees
  ring[29] = 5;
  ring[30] = 5;
  ring[31] = 5;
  ring[32] = 5;
  ring[33] = 5;
  ring[34] = 6;      //  150 degrees
  ring[35] = 6;
  ring[36] = 6;
  ring[37] = 6;
  ring[38] = 6;
  ring[39] = 6;
  
  for(i=0;i<4;i++)
    Ge_Ener_Gate[i].set_Gate(0,4095); // Gate open to Gamma-Gamma
  Ge_Time_Gate.set_Gate(0,4095);      // Time Gate Open
  
  BGO_Ban.set_Zero();          // Gate Closed No BGO K-H Selection
  
  read_file();      // Read Initial Values from file if it exists
          for(ii=0;ii<256;ii++)
            for(jj=0;jj<256;jj++)
              if(BGO_Ban.Banana(ii,jj))
                for(kk=0;kk<1000;kk++)
                  Mat_Bgo_Ban.inc(ii,jj);
// End Initialisations

  int evNum = 0;
  int flush = 0;
  while(1) {
    try {
      if(do_read_file)  // if read_file flag is set read file with params.
        read_file();
      event.next();
      evNum++;
      classif.inc(60);
        if(flush++ == 5000) { base_histo::flush(); flush = 0;}
      int ErrorSum = 0;
        howManyB= B.howManyFired();
        howManyG= G.howManyFired();
      if(ErrorSum == 0 || ErrorSum == 10) {
          if(event.isBad()) { 
            classif.inc(100);
            for(int kk=0;kk<event.classification.size();kk++) {
              if(event.classification[kk])
                ErrorSum += kk;
            }
          }
          if(howManyG > 0) {            // 1 Ge minimum
            classif.inc(110+howManyB);        // count detectors firing
            classif.inc(120+howManyG);
            classif.inc(150);            // and All events
// BGO BALL
          if(howManyB == 1) {
            Bgo_Mult.inc(B(0).bgo_count);
            Bgo_Esum.inc(B(0).bgo_ener);
            kbval = B(0).bgo_count/16;
            hbval = B(0).bgo_ener/16;
            Mat_Bgo.inc(kbval,hbval);
          }
          printf("Original BGO Values : %d %d\n",(short)B(0).bgo_count,(short)B(0).bgo_ener);
          
          printf("Scaled BGO Values : %d %d\n",kbval,hbval);
          printf("BananaValue : %d\n",BGO_Ban.Banana(kbval,hbval));
          if(BGO_Ban.Banana(kbval,hbval)) {
            BGO_K_Gate.inc(B(0).bgo_count);
            BGO_H_Gate.inc(B(0).bgo_ener);
            for(j=0;j<howManyG;j++)
              Ge_BGO_Gated.inc((long)G(j).ener);
//            Mat_Bgo_Ban.inc(kbval,hbval);
          }

          if(recoil_vc >= 0.0) {    // if v/c has changed
            recoil_vc = recoil_vc*0.01;      // new recoil velocity
            if(recoil_vc > 0.5) {         // a bit too fast
              recoil_vc = 0.;          // disable doppler
              for(i=0;i<40;i++)                      
                doppler[i] = 1./(1.0 + recoil_vc*costheta[i]);  
              recoil_vc = -1.0;          // wait for a new value
            }
          }
// Germani
// Fa tutto qui dentro, Calibrazione, Doppler, spettri e Rings 
          for(i=0;i<G.howManyFired();i++) {  // For each Ge in the event
            detKey = G(i).keyGet();
            geval = G(i).ener;
            if(geval > 0) {          // update pseudo random number
              rnd_val = rnd_val+rnd_step;
              if(rnd_val >= rnd_mod)
                rnd_val = rnd_val-rnd_mod;
              rnd_num = rnd_val*rnd_rnd;
              rtmp = geval + rnd_num + 1.0;  // and apply it
              
              geval = ge_ecal[detKey][0]+
                (ge_ecal[detKey][1]+(ge_ecal[detKey][2]+
                ge_ecal[detKey][3]*rtmp)*rtmp)*rtmp; // apply Calibration
                
              geval *= doppler[detKey]*ge_egain-1.0;   //  ,doppler & gain
              geval = geval < 0 ? 0 : (geval > 4095 ? 4095 : geval);
              G(i).ener = (short) geval;
            }    
            gtval = G(i).time;
            if(gtval > 0) {
              gtval += ge_tshift[detKey];  // Shift time
              tval = gtval < 0 ? 0 : (gtval > 4095 ? 4095 : gtval);
              G(i).time = (short)gtval;
            }                // Increment:
            Ge_Ener[detKey].inc(geval);      // each calibrated Energy
            Ge_E_All.inc(geval);        // the sum of all Ge Energy
            Ge_Rings[ring[detKey]].inc(geval);  // the rings
            Ge_Time[detKey].inc(gtval);      // each shifted Time   
            Ge_T_All.inc(gtval);        // the sum of all Ge Time
          }
          
// This gate could be performed earlier          
          int  geTimeIsInGate;
          if(geTimeIsInGate = Ge_Time_Gate.Gate(gtval)) {  // check Time Gate
            Ge_T_Gate.inc(gtval);        // increment gate window spectrum
//  Ge_Rings[ring[detKey]].inc(geval);  // and time gated rings
          }else{
            G(i).invalidate();
          }
          howManyG = G.howManyFired();  // recalculate remaining Ge's
          if(howManyG > 1) {      // If remains more than 1 Ge     
            for(k=0;k<4;k++) {    // Perform Single and Double gamma-Gate
              for(i=0;i<howManyG;i++) {
                if(Ge_Ener_Gate[k].Gate((long)G(i).ener)) { // if Gate ok
                  Ge_E_Gate[k].inc(G(i).ener);      // increment gate
                  for(j=0;j<howManyG;j++) {
                    if(i != j) {
                      Ge_E_SGated[k].inc(G(j).ener);  // single gated spectra
                      if(Ge_Ener_Gate[k].Gate((long)G(j).ener)) {
                        if(howManyG> 2) {
                          for(m=0;m<howManyG;m++) {
                            if(m != i && m != j) { // double Gated spectra
                              Ge_E_DGated[k].inc(G(m).ener);
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        } 
      }
    }catch (RWxmsg & x) { cerr<<x.why()<<endl; }
  }
}

// Subroutines used to change the value of some parameters following a USR Signal

// exit = 1 -> File not found

int  read_file()      // Read the usrAction.txt file descibing what action is requested
{
  FILE    *fd_act;
  char    string[30];
  int    exit = 0;
  
  int    par;
  int    i;
  
  fd_act = fopen("/Gasp_Users/Config/usrAction.txt","r");
  if(fd_act) {
    printf("Reading action file !!\n");
// insert here the read_file code
// add ge_gain and V/C from file
// add ISIS calib and shift
    while(fscanf(fd_act,"%s",string) == 1) {
      if(strstr(string,"Ge_co_cal")) {
        read_calib(0);
        cout<<"Out of Ge_co_cal"<<endl;
      }
      else if(strstr(string,"Ge_df_cal")) {
        read_calib(1);
        cout<<"Out of Ge_df_cal"<<endl;
      }
      else if(strstr(string,"Ge_shift")) {
        read_shift(0);
        cout<<"Out of Ge_shift"<<endl;
      }  
      else if(strstr(string,"Doppler"))  {
        fscanf(fd_act,"%f",&recoil_vc); 
        cout<<"Out of Doppler"<<endl;
      }
      else if(strstr(string,"Gain"))     {
        fscanf(fd_act,"%f",&ge_egain);
        cout<<"Out of Gain"<<endl;
      }
      else if(strstr(string,"BGO_Ban"))  {
        read_banana(0);
        cout<<"Out of Banana"<<endl;
      }
      else if(strstr(string,"Ge_Gate"))  {
        fscanf(fd_act,"%d",&par);
        switch (par) {
          case 0:    // Germanium energy gate
            fscanf(fd_act,"%d",&howManySets);
            if(howManySets > 0 && howManySets < 4) {
              for(i=0;i<howManySets;i++) {
                fscanf(fd_act,"%d %d",&low,&high);
                printf("Ge Energy Gate: Set# %d %d %d \n",i,low,high);
                Ge_Ener_Gate[i].set_Zero();
                Ge_Ener_Gate[i].set_Gate(low,high);
              }
            }
            break;
          case 1:    // Germanium time gate
            fscanf(fd_act,"%d %d",&low,&high);
            printf("Ge Time Gate: %d %d \n",low,high);
            Ge_Time_Gate.set_Zero();
            Ge_Time_Gate.set_Gate(low,high);
            break;
        }
      }
    }
  }else
    exit=1;            // File not found
  do_read_file = 0;
  fclose(fd_act);
  return exit;
}

// exit = 1 -> File not found
// exit = 2 -> Missing Valid header
// exit = 3 -> Index out of range
// exit = 4 -> Too many points

int read_calib(int det)    // Read Energy calibration coefficients from specific files
{
  FILE    *fd_in;
  char    string[101];
  float     a,b;
  int      detPos=-1,exit=0;
  
  switch (det) {
    case 0:    // Germanium
      fd_in = fopen("/Gasp_Users/temp/Calibrations/ge_ener.co60","r");
      break;
    case 1:    // Germanium
      fd_in = fopen("/Gasp_Users/temp/Calibrations/ge_ener.cal","r");
      break;
  }  
  if(fd_in){
    printf("File found\n");
    fgets(string,100,fd_in);
    cout<<string<<endl;
    if(strstr(string,"INIT_DATA")) {
      printf("Correct Header\n");
      fgets(string,100,fd_in);
      while (strlen(string) && !exit && ! strstr(string,"END_DATA")) {
      printf("Correct Header, Entering do loop \n");
        if(sscanf(string,"%2d %f %f",&detPos,&a,&b) == 3) {
          printf("record with 3 values %d %f %f\n",detPos,a,b);
          if(detPos >= 0 && detPos <= 40) {
            printf("Correct Index\n");
            switch (det) {
              case 0:    // Germanium
                ge_ecal[detPos][0] = a;
                ge_ecal[detPos][1] = b;
                ge_ecal[detPos][2] = ge_ecal[detPos][3] = 0;
                break;
              case 1:    // Germanium
                ge_ecal[detPos][0] = a;
                ge_ecal[detPos][1] = b;
                ge_ecal[detPos][2] = ge_ecal[detPos][3] = 0;
                break;
            }
          }else{
            exit = 3;    // Index out of Range
          }
        }
        fgets(string,100,fd_in);
      }
      printf("Exiting do loop \n");
    }else{
      exit = 2;          // Missing Valid Header
    }
    fclose(fd_in);
  }else{
    exit = 1;            // File not found
  }
  return exit;
}

// exit = 1 -> File not found
// exit = 2 -> Missing Valid header
// exit = 3 -> Index out of range
// exit = 4 -> Too many points

int read_shift(int det)    // Read Time calibration coefficients from specific files
{
  FILE    *fd_in;
  char    string[101];
  int     a;
  int      detPos,exit=0;
    
  switch (det) {
    case 0:    // Germanium
      fd_in = fopen("/Gasp_Users/temp/Calibrations/ge_time.cal","r");
      break;
  }  
  if(fd_in) {
//    printf("File found\n");
    fgets(string,100,fd_in);
    if(strstr(string,"INIT_DATA")) {
//      printf("Correct Header\n");
      fgets(string,100,fd_in);
      while (strlen(string) && !exit && ! strstr(string,"END_DATA")) {
//        printf("Correct Header, Entering do loop \n");
        if(sscanf(string,"%d %d ",&detPos,&a) == 2) {
//          printf("record with two values %d %d \n",detPos,a);
          if(detPos >= 0 && detPos <= 40) {
//              printf("Correct Index\n");
            switch (det) {
              case 0:    // Germanium
                ge_tshift[detPos] = a;
                break;
            }
          }else
            exit = 3;  // Index out of Range
        }
        fgets(string,100,fd_in);
      }
    }else{
      exit = 2;          // Missing Valid Header
    }
    fclose(fd_in);
  }else{
    exit = 1;            // File not found
  }
  return exit;
}

// exit = 1 -> File not found
// exit = 2 -> Missing Valid header
// exit = 3 -> Index out of range
// exit = 4 -> Too many points

int read_banana(int type)    // Read Banana poligon 
{
  FILE    *fd_in;
  char    string[101];
  int     a,b,ii;
  long    si_polyX[100],si_polyY[100];
  int      exit=0;
  
  switch (type) {
    case 0:    // BGO
      fd_in = fopen("/Gasp_Users/temp/Calibrations/current/BGO_Ban.ban","r");
      break;
  }  
  if(fd_in){
    printf("File found\n");
    fgets(string,100,fd_in);
    if(strstr(string,"INIT_DATA")) {
      printf("Correct Header\n");
      ii = 0;
      fgets(string,100,fd_in);
      while (strlen(string) && !exit && ! strstr(string,"END_DATA")) {
        printf("Correct Header, Entering do loop \n");
        if(sscanf(string,"%d %d",&a,&b) == 2) {
          printf("record with two values %d %d \n",a,b);
          si_polyX[ii]   = a;
          si_polyY[ii++]  = b;
          if(ii > 99)
            exit = 4;    // Too many points;
        }
        fgets(string,100,fd_in);\
      }
      printf("Exiting do loop \n");
    }else{
      printf("%s\n",string);
      exit = 2;          // Missing Valid Header
    }
    fclose(fd_in);
    if(! exit) {
      switch (type) {      // exit = 5 not a closed Polygon
        case 0:    // BGO
          BGO_Ban.set_Zero();
//          BGO_Ban.set_Banana((long)2,(long)255,(long)2,(long)255);
          cout << "Banana Set" << endl;
          exit = 5*BGO_Ban.set_Banana(ii,si_polyX,si_polyY);
// show the Banana region
          break;
      }
    }
  }else{
    exit = 1;            // File not found
  }
  cout << "Error : " << exit << endl;
  return exit;
}
Go to Index

Other useful directories:
gaspux4:/Gasp_Users/save

Content: Set of Spectrum Files saved by the XmSpecview Program

gaspux4:/Gasp_Users/temp

Content: Set of Folders with temporary information

gaspux4:/Gasp_Users/temp/OP_Files

Content: Set of Folders with Spectrum Operation descriptors

gaspux4:/Gasp_Users/temp/Calibrations

Content: Set of Files with temporary Calibration, Shift and Gain files.
.60Co extension for the 60 Cobalt gamma calibration files
.cal extension for the generic calibration files

gaspux4:/Gasp_Users/temp/Calibration/current

Content: Set of Files with Banana Poligons and other current related information

Go to Index


XmSpecview.It is an updated version of the one written by Mario DePoli and running under Unix in the HP730.


Menu:

FILE

Add to Display Adds one more spectrum to the display layout

from Histoserver... Reads the spectra from produced by the Neo++ programs.
from Disk...Reads the spectra from the saved folder on the Disk.

Create OP Spectra... Creates an operation spectra. See the Help for more details.
Replace Display Config. Load a display Configuration from the display Folder in the current experiment directory.
Save Level 0 Config. Save the current display Configuration into the display Folder in the current experiment directory.
Save Spectra. Saves the spectra into the Gasp_Users/save Folder according to the format selected by the Menu DEFINE/Disk File format...

Selection.
Screen
All Screens

HARDCOPY (not used)
Single Spectra
Screen
Ps Printer Allows selecting the hardcopy printer.

EDIT

Select All. Selects all spectra of the present screen.
Unselect All. Unselects all spectra of the present screen.
New View Level 1: Selected Opens a new view using only the selected spectra.
Previous View Level * Allows descending one level in the view
Remove Selected. Remove the selected spectra from the view. If the view is the level 0, the spectra are removed from the viewer.
Reposition Selected. Performs rearrangement operations.

Swap Spectra
Move First Spectrum

Regions on Selected. Saves or removes regions of Interest.

SCREENS. Allows selecting one of the 16 available screens.

HISTOG

UPDATE. Updates the spectra according with the following criteria.

Selected
Screen
Level 0 Screen

ERASE. Erases the spectra according with the following criteria.

Selection
Screen
All Screens

DISPLAY

Display Behaviour

Indipendent & Frames. Each spectra has its own frame and scale control bars.
Homogeneous. All spectra have the same scale and common scale control bars.
X-Homogeneous. The spectra have indipendent vertical scales and controls and common horizontal scale and controls.

Display Layout. Allows selecting the spectra layout.

Vertical.
Horizontal.
Row Mayor.
Column Mayor.

Drawing Scales. Allows selecting the proper X-Y scale combination

X Axis Scale

Linear

Y Axis Scale

Linear
Logarithmic
Square Root

X Axis Type

Chan zero Included
Chan zero Excluded

Y Axis Type

0-Max
Min-Max
Simmetric

Drawing Options

Show Overlay. Show the spectra and any associated overlay.
No Clear. Do not clear the existing spectra at the next operation.
Show Work Regions. Show the working regions associated with the spectra
Show Saved Regions. Show the Saved Regions associated with the spectra.

DEFINE

Screen Names... Opens a window allowing to type the screen names.
Peak Width... Allows selecting the aproximate peak width to be used in the peak searching routine.
Good Resolution... Allows to establish what is upper limit of the gamma resolution.
Timer Interval ...Selects the timer interval for repeated operations. If 0 no timer is activated. When de timer is active the DEFINE label appears Red coloured.
Disk File Format ... Selects the disk file format of the saved spectra.

ACTIONS. See more details in the Menu Help.

Show Results. Opens a new window where all calculations are summarised.
Calculate. Performs the selected calculations.

Integral. Uses the I, B and J regions
Gauss Fit. Uses the R and Q regions and the G markers.

Peak Search. Performs a peak searching calculation.
Recal_Cob Performs a global energy linear calibration assuming a 60Co source.
Adjust_Time Performs a shift calibration. Used for Timing alignment.
Eval_Doppler Performs a Doppler estimate.
Adjust_Gain Performs a gain calculation. Used to gain adjust particle spectra.

HELP. Text descrption of the main features of the program.

Go to Index


XmMatview. It is an updated version of the one written by Mario DePoli and running under Unix in the HP730.


Go to Index