Pixie16 Analysis Software Suite
Analysis code for processing of .ldf files
|
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
For more information on any of the topics mentioned here you are referred to the fantastic resource cplusplus.com. This webpage has many thorough descriptions of the ideas presented here, as well as, a complete method listing for the STL templates discussed.
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. Functions that are contained within classes are called "methods". 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 GeProcessor, which performs much more complex manipulations of data that is taken using Ge detectors. In the analysis, all classes consist of two different files: a '.hpp' file, and a '.cpp' file. The '.hpp' file defines the class, its data members, and the methods that allow a user to manipulate the data members. The ".cpp" file contains the code necessary for the class to do what you want. The following code shows an example for the class called ChanEvent that contains the information for each channel that triggered. Below, we list the content of ChanEvent in its entirety.
In the ChanEvent example, all the data members are defined as private and methods that act on the data members are public. This means that only the methods belonging to this class such as GetEnergy() 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.hpp file).
The arguments that must be passed to a method are defined between the parenthesis after the method's name. Thus, the method SetEnergy() must be provided a double-precision numerical value in order to work properly and would look like the following:
The other important aspect of the methods are their return values, which is defined before the method name. For example, the method GetEnergy() returns the value contained in the variable energy which is a double. Therefore to correctly retrieve the value you need to use a double.
Arguments to methods and results thereof are not limited to basic data types (int, double, char, ...) but can include other objects as well. In the method, GetChanID() method an Identifier object is returned. When using any of the methods make sure you know what type of argument is required.
Methods that are defined in the ".hpp" file of the class are said to be defined "inline". Most of the methods in ChanEvent are defined inline. One exception is ZeroVar() which is defined in the corresponding '.cpp' file; a portion of which is shown below:
\snippet ChanEvent.cpp Zero Channel
The only exception to this *.hpp and *.cpp pattern is PixieStd.cpp No class is defined for PixieStd because the main function hissub_ is called from the FORTRAN scan program. A class could probably be constructed but is not strictly necessary in this case.
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. An example usage is:
In this section of code a pointer by value 'chan' is created that that will point to a ChanEvent object. The second line puts the memory location of eventList[1] (a ChanEvent 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 eventList[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:
Where a reference to the variable passed to the function is received.
The vector class 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
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.
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
will print out a value of 5.
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. Using iterators is, by far, the safest way to access the contents of the vector because an out of bound failure is much more descriptive than simply "Segmentation Fault".
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
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.
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.
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 is a powerful method to associate an unknown number of detector types with data objects as is done in the pixie16 analysis.