[Feedback][Tutorial Contents][hep.lcd Home]
![]()
In the previous tutorial you used a pre-written analysis module to analyze some LCD data and create histograms. In this tutorial we will show you how to write your own analysis routines, and how to understand the structure of the LCD data.
When you write analysis code in Java Analysis Studio you normally create a new class, such as MyAnalysis which extends a base class called EventAnalyzer. EventAnalyzer is a sort of no-op analysis which provides the framework for doing analysis, but doesn't actually do any specific analysis. By extending it your "MyAnalysis" class automatically inherits all of the framework, but can extend it to actually do some useful analysis. Typically you do this by overriding a single method called processEvent. The processEvent method is called by the framework each time a new event is ready for analysis.
Lets look in detail now at the processEvent method from the previous tutorial, and go through it line by line explaining what is going on.
public void processEvent(EventData d)
{
LCDEvent header = (LCDEvent) d;
The first line declares the processEvent method. It must be public (so the framework can call it) and void (it doesn't return anything). The argument to the processEvent method is the event to be analyzed. Since the Java Analysis Studio is experiment independent, the event passed to the processEvent method is of a generic EventData type, but since we know what type of data we want to analyze (in this case LCD data) we can cast the input object to an LCDEvent.
LCDEvent is defined as part of the hep.lcd classes, and is an event header that occurs
in each LCD event. From the LCDEvent class it is possible to navigate to the rest of the
event data. There are a lot of classes defined in hep.lcd, but you will not need to refer
to most of the classes unless you want to write your own reconstruction modules. To do
data analysis you just need to know about the relatively few hep.lcd.event classes, of
when LCDEvent is one. You can find detailed documentation on the hep.lcd.event classes
here. In the rest of this tutorial we will
include a link to the detailed documentation on new classes as we introduce them, like
this: LCDEvent
.
Continuing with our analysis routine:
CalorimeterHits hits = header.getEMCalorimeterHits();
double EMEnergy = sumEnergy(hits.getHits());
The first line here declares a variable called hits, which is a reference to an
object of type CalorimeterHits
. This variable is initialized to refer
to a CalorimeterHits object, obtained from the LCDEvent by calling the
getEMCalorimeterHits() method (which returns the hits in the EM Calorimeter). The second
line defines a variable of type double and sets it to the result of calling the sumEnergy
routine that we will describe later. Note that it is common practice to always use double
for floating point variables since with most computers today the overhead of using double
instead of float is trivial.
histogram("EM nhits").fill(hits.getNHits()); histogram("EM Energy").fill(EMEnergy);
These two lines produce the first two histograms. Note that it takes only one line to declare and fill a histogram, which makes adding histograms to programs in Java Analysis Studio very straightforward.
In more detail what is happening here is that we are calling a method called histogram
which takes a String argument (the histogram name) and returns a Histogram
object, we are then calling the fill
method of the Histogram object, which takes a single numeric argument (the value to fill
into the histogram).
The histogram method is a framework method that our class inherited from the EventAnalyzer
class. It looks for a named histogram
and returns a reference to the corresponding Histogram object. If a Histogram of the given
name does not exist it creates a new Histogram and returns that.
hits = header.getHADCalorimeterHits();
double HADEnergy = sumEnergy(hits.getHits());
histogram("HAD nhits").fill(hits.getNHits());
histogram("HAD Energy").fill(HADEnergy);
hits = header.getMuonCalorimeterHits();
histogram("MU nhits").fill(hits.getNHits());
histogram("MU Energy").fill(sumEnergy(hits.getHits()));
histogram("Total Energy").fill(EMEnergy/0.017 + HADEnergy/0.071);
}
The remainder of the processEvent method should be self-explanatory, just repeating what we have already seen for hadron calorimeter hits followed by the muon calorimeterHits, and then finally histogramming the sum of the energy in the EM and HAD calorimeters.
private double sumEnergy(Enumeration e) { double energy = 0; while (e.hasMoreElements()) { CalorimeterHit hit = (CalorimeterHit) e.nextElement(); energy += hit.getEnergy(); } return energy; }
The remainder of the analysis routine is the definition of the sumEnergy method. The
sumEnergy method is only called from within this same class, so it is declared private,
and it returns a double. The argument to the routine is an object of type Enumeration
. Enumeration is a Java utility class
(from the package java.util) which provides a means of looping over a collection of
objects without knowing the organization of the collection. Looking back at the places
where sumEnergy was called you can see that in each case we obtained an Enumeration of the
hits from the appropriate CalorimeterHits collection and passed that as the argument.
The body of the sumEnergy method simply loops over the elements of the Enumeration,
using the methods in Enumeration to check if more elements exist, and if so to fetch the
next element. Since an Enumeration can contain any type of object, the nextElement method
returns an Object, however since we know the collections will in fact consist of
CalorimeterHit
objects, we can cast the result and use
the CalorimeterHit.getEnergy method to extract the energy of the hit.
Finally lets look at the entire analysis routine to see what boilerplate code we need to make a complete analysis routine.
import hep.analysis.*; import hep.lcd.event.*; import java.util.*; public class LCDResolution extends EventAnalyzer { public LCDResolution() { } public void processEvent(EventData d) { LCDEvent header = (LCDEvent) d; CalorimeterHits hits = header.getEMCalorimeterHits(); double EMEnergy = sumEnergy(hits.getHits()); histogram("EM nhits").fill(hits.getNHits()); histogram("EM Energy").fill(EMEnergy); hits = header.getHADCalorimeterHits(); double HADEnergy = sumEnergy(hits.getHits()); histogram("HAD nhits").fill(hits.getNHits()); histogram("HAD Energy").fill(HADEnergy); hits = header.getMuonCalorimeterHits(); histogram("MU nhits").fill(hits.getNHits()); histogram("MU Energy").fill(sumEnergy(hits.getHits())); histogram("Total Energy").fill(EMEnergy/0.017 + HADEnergy/0.071); } private double sumEnergy(Enumeration e) { double energy = 0; while (e.hasMoreElements()) { CalorimeterHit hit = (CalorimeterHit) e.nextElement(); energy += hit.getEnergy(); } return energy; } }
The full name of the LCDEvent class (for instance) is hep.lcd.event.LCDEvent. To avoid having to always specify the entire long name each time we use it, we can use the import statement. The import statement is used to import a namespace into the current routine, so that the abbreviated name can be used. In this case we start the routine by importing three namespaces, hep.lcd.event (used for LCDEvent, CalorimeterHits and CalorimeterHit classes), java.util (used for Enumeration) and hep.analysis (used for Histogram and EventAnalyzer).
Next we declare the class itself, in this case called LCDResolution, which as we have explained before extends the framework routine EventAnalyzer. Finally we declare a public constructor for the LCDResolution class which takes no arguments, so that the class can be created by the framework. Constructors always have the same name as the class itself, and have no declared return type. If we needed to do some initialization we could do it in the body of the class constructor, but in this case there is no initialization needed, so the constructor body is empty.
The remaining tutorials in this series contain several more examples of writing analysis routines. Other resources that may be useful: