[Feedback][Day 1][Day 2][Welcome Page]
In the previous tutorial you used a pre-written analysis module to analyze some MC 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
Driver. Driver is a sort of no-op analysis which provides the framework for
doing analysis, but doesn't actually do any specific analysis. By extending Driver 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
process. The process method is called by the framework each time a new event is
ready for analysis.
Lets look in detail now at the process method from the previous tutorial, and go through it line by line explaining what is going on.
// Called by the framework to process each event public void process(LCDEvent event) {
The first line declares the process method. It must be public (so the framework can call it) and void (it doesn't return anything). The argument to the process method is the event to be analyzed. Since the Driver class is specific to LCD, the event passed to the process method is 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 which 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:
// Loop over the MC particles ParticleVector list = event.getMCParticles(); Enumeration e = list.particles(); double etot = 0; while (e.hasMoreElements()) {
The first line here declares a variable called list, which is a reference to an object of type ParticleVector. This variable is initialized to refer to a ParticleVector object, obtained from the LCDEvent by calling the getMCParticles() method. Since we want to loop over all of the particles we must first obtain an Enumeration of the particles. An Enumeration is a built-in Java class that makes it easy to loop over collections of objects without knowing about the detailed organization of the collection. The while loop is used to actually do the looping.
MCParticle mc = (MCParticle) e.nextElement(); // histogram particle energy double energy = mc.getEnergy(); cloud1D("Particle Energy").fill(energy);
The first line here assigns the variable mc to point to the current MCParticle. MCParticle is an LCD specific class which extends the general purpose Particle class. Most of the useful methods are defined as part of the Particle class. In this example we extract the energy of the particle using the getEnergy() method, and then create a histogram of the particle energy. Note that it takes only one line to declare and fill a histogram, which makes adding histograms to programs in JAS3 very straightforward.
// reject non final state particles cloud1D("Particle Status").fill(mc.getStatusCode()); if (mc.getStatusCode() != mc.FINALSTATE) continue;
In the next lines of the program we create and fill another histogram, this time with the particle status code (which can be one of FINALSTATE, INTERMEDIATE or DOCUMENTATION). We reject the particle if it is not a final state particle. The continue statement causes execution to switch to the next iteration of the while loop without executing the rest of the body of the while loop.
// reject neutral particles ParticleType type = mc.getType(); int charge = (int) type.getCharge(); cloud1D("Particle Charge").fill(charge); if (charge == 0) continue;
These lines are very similar to the last set, this time we are getting the particles charge, histogramming it and rejecting neutral particles. The MCParticle class does not have a getCharge() method, but instead has a getType() method that returns a ParticleType object, from which we can extract the charge.
// Some more histograms String name = type.getName(); cloud1D(name + "-Energy").fill(energy);
Here we extract the name of the particle type as a String, and use it as part of the histogram name to create a separate histogram for each particle type.
The remainder of the process method should be self-explanatory, we add each particles energy to etot, and then finally, outside the while loop, we fill a histogram of etot.
etot += energy; } cloud1D("etot").fill(etot); }
Finally lets look at the entire analysis routine to see what boilerplate code we need to make a complete analysis routine.
import hep.physics.*; import hep.lcd.util.driver.*; import hep.lcd.event.*; import java.util.*; import hep.aida.*; public class MyAnalysis extends Driver { // Called by the framework to process each event public void process(LCDEvent event) { System.out.println(event); // Loop over the MC particles ParticleVector list = event.getMCParticles(); cloud1D("nMC").fill(list.size()); Enumeration e = list.particles(); double etot = 0; while (e.hasMoreElements()) { MCParticle mc = (MCParticle) e.nextElement(); // histogram particle energy double energy = mc.getEnergy(); cloud1D("Particle Energy").fill(energy); // reject non final state particles cloud1D("Particle Status").fill(mc.getStatusCode()); if (mc.getStatusCode() != mc.FINALSTATE) continue; // reject neutral particles ParticleType type = mc.getType(); int charge = (int) type.getCharge(); cloud1D("Particle Charge").fill(charge); if (charge == 0) continue; // Some more histograms String name = type.getName(); cloud1D(name + "-Energy").fill(energy); etot += energy; } cloud1D("etot").fill(etot); } }
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 five namespaces, hep.lcd.event (used for LCDEvent, CalorimeterHits and CalorimeterHit classes), java.util (used for Enumeration), hep.aida (used for analysis objects), hep.physics (used for Particle, ParticleVector and ParticleType) and hep.lcd.util.driver (used for Driver).
Next we declare the class itself, in this case called MyAnalysis, which as we have explained before extends the framework routine Driver. The class must be declared public for JAS to be able to access it. There is no explicit constructor declared for the class since Java always assumes a zero-argument public constructor if none is specified. If we needed to do some initialization we could do it in the body of the class constructor.
The remaining tutorials in this series contain several more examples of writing analysis routines. Other resources that may be useful:
Go to the next tutorial.