Primer

In this section I will attempt to provide a rough description of the aspects of C++ that are being used in the analysis code that someone who has never seen C++ before may not recognize. Described here are

Classes

The C++ code is structured around classes. Classes are very similar to structures in C, and are objects into which data is placed or actions are performed. For example the class rawevent is the basic object into which all event data will be placed in the analysis. Another example is the class Correlator which performs a decay-implant correlation using a rawevent object. In the analysis, all classes consist of two different files, a '.h' file defines the class, its data members, and the functions that allow a user to manipulate the data members. The following code shows an example for the class called chan_event which contains the information for each channel that triggered.
// file rawevent.h - class chan_event \\
   class chan_event{
     private:
       double energy;                           
       double cal_energy;
       double time;
       double cal_time;
       vector<int> trace;
       identifier chanid;
     public:
       int    id;
       void Set_id(int a)            {id = a;}
       void Set_energy(double a)     {energy = a;}
       void Set_cal_energy(double a) {cal_energy = a;}
       void Set_time(double a)       {time = a;}
       void Set_cal_time(double a)   {cal_time = a;}
       void Add_trace(int a)         {trace.push_back(a);}
       void Set_chanid(identifier a) {chanid = a;}

       int    Get_id()               {return id;}
       double Get_energy()           {return energy;}
       double Get_cal_energy()       {return cal_energy;}
       double Get_time()             {return time;}
       double Get_cal_time()         {return cal\_time;}
       vector<int>  Get_trace()      {return trace;}
       int Get_trace_val(int a)      {return trace[a];}
       identifier Get_chanid()       {return chanid;}
       void zerovar();
       }; 
In the chan_event example all the data members are defined as private and functions that act on the data members are public. This means that only the functions belonging to this class such as Get_energy() can access the private data members. This prevents the variables from being inadvertently altered by a different portion of the analysis code. I've tried to keep all data members private but haven't in all cases just for simplicity (for example see the rawevent class in the rawevent.h file).

The arguments that must be passed to a function are defined between the parenthesis after the functions name. Thus, the function Set_energy must be provided a double numerical value in order to work properly and would look like the following:

  Set_energy(3.145);
Arguments to functions are not limited to basic data types (int, double, char, ...) but can include other objects as well. In the Set_chanid function an identifier object must be given. When using any of the functions make sure you know what type of argument is required. The other important aspect of the functions are their return values, which is defined before the function name. For example, the function Get_energy() returns the value contained in the variable energy which is a double. Therefore to correctly retrieve the value you need to use a double.
  double tempenergy;
  tempenergy = Get_energy();

Functions that are defined in the ".h" file of the class are said to be defined "inline". All of the functions in chan_event are defined inline with the exception of zerovar which is defined in the corresponding *.cpp file, a portion of which is shown below:

  // file rawevent.cpp - zerovar()
  void chan\_event::zerovar(){
    id = -1;
    energy = -1;
    cal_energy = -1;
    time = -1;
    cal_time = -1;
    trace.clear();
    chanid.zeroid();
  } 
The only exception to this *.h and *.cpp pattern is the pixie_std.cpp file. No class is defined for pixie_std because the main function hissub_ is called from the FORTRAN scan program. A class could probably be constructed but I didn't want to mess with it.

Pointers

Pointers are both an incredibly powerful feature of C++ and the easiest way to screw up the code. The two types of pointers in C++ are a pointer by value and a pointer by reference. A pointer by value is declared by an '*' in the C++ code and points to the value contained in a variable. A pointer by reference is declared by an '&' in the C++ code and points to the memory location where a variable is stored. The most common usage that the pointers receive in the analysis code is demonstrated in the following few lines of code.
  // file detector_driver.cpp - process_event(rawevent &)
  chan_event *chan;
  chan = &revt.event1[1];
In this section of code a pointer by value 'chan' is created that that will point to a chan_event object. The second line puts the memory location of revt.event1[1] (a chan_event object) into the pointer chan. In this way it is possible to perform actions on chan and have it affect the values contained in the variable revt.event1[1].

Functions also rely heavily on pointers. By default when a C++ function is passed a variable a local copy is created inside the function. This means that if a value is passed to a function in this manner the function can use the value and alter it but after the function is finished the local copy of the value disappears, and the original is not affected. In general, it is far more useful to have a function act on and permanently alter the original value. This is where pointers are useful. A pointer by reference or value can be passed to a function and actions on the pointer will affect the original data. The passing of pointers is also much less computationally intensive speeding up the data analysis. For example, a function declared to receive a pointer by reference would look like:

  int threshandcal(int &i);
Where a reference to the variable passed to the function is received.

Vector

The vector variable is part of the STL (standard template library) that is used in the analysis. A vector is essentially a dynamically expandable array. A vector variable is defined as
  vector<int> intvec;
where intvec is declared as a vector that contains integer values. The two common functions that are used to act on vectors include the push_back and clear functions.
  intvec.push_back(2);
  intvec.push_back(5);
  intvec.clear();
The push_back function inserts a value at the end of the vector. In this example the first element of the vector intvec will have a value of 2 and the second element is 5. The clear() function removes all entries in a vector and is extensively used in the code to zero the various vectors that are used. The values of a vector can be retrieved in two different ways. First, you can ask for a specific element using the same syntax as an array, thus
  cout << intvec[1] << endl;
will print out a value of 5.

Warning:
C++ index numbering starts at 0 not at 1 as in FORTRAN. Let me repeat since this causes many problems if forgotten. C++ index numbering starts at 0 not at 1 as in FORTRAN.
The second way to retrieve a value from a vector is through an iterator. This is a pointer that can be pointed any location in the array to retrieve the value at that location. The following section of code would loop over the intvec from beginning to end and print the value of the element. Note the incrementing of the iterator iv using iv++ to go to the next element.
  vector<int>::iterator iv;
  iv = intvec.begin()
  while(iv != intvec.end())
  {
     cout << *iv << endl;
     iv++;
  }

Map

The map is the other STL feature used in the code. The map allows an association between an unique key and a value. It is defined as
  map<string,int> stringintmap;
In this example the key is a string and the associated value is an int. To create a map you have to make pairs of the keys and values as in the following example.
  stringintmap.insert(make_pair("dssd",2));
  stringintmap.insert(make_pair("ge",15));
In this example the key "dssd" is associated with an integer of 2 and the key "ge" is associated with an integer of 15. The associated values can be retrieved either by a direct access using the key or using of the find function.
  int temp;
  temp = stringintmap["dssd"];
  
  int temp1;
  temp1 = stringintmap.find("ge");
where temp and temp1 will return 2 and 15 respectively. While associating strings with integers is not very useful a map of strings associated with objects powerful method to associate an unknown number of detector types with data objects as is done the in the pixie16 analysis.

Warning:
I am not a C++ expert! It is possible that in the analysis code things are done inefficiently. Also, the descriptions I have given above may not be completely accurate but instead reflect a lack of understanding on my part. Keep that in mind when reading the manual and the code. If you think things could be done differently for clarity or processing speed please let me know.

Generated on Wed May 14 10:07:06 2008 for pixie16 by  doxygen 1.5.5