[Feedback][Day 1][Day 2][Welcome Page]

shoeline2[1].gif (1488 bytes)

Writing Your Own Analysis Code

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(in the API reference documentation).

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(in the API reference documentation). 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(in the API reference documentation) 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(in the API reference documentation). MCParticle is an LCD specific class which extends the general purpose Particle(in the API reference documentation) 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.

  1. In more detail what is happening here is that we are calling a method called cloud1D which takes a String argument (the histogram name) and returns a ICloud1D(in the API reference documentation) object, we are then calling the fill method of the ICloud1D object, which takes a single numeric argument (the value to fill into the histogram). The cloud1D method is a framework method that our class inherited from the IHistogramManager(in the API reference documentation) class. It looks for a named cloud and returns a reference to the corresponding ICloud1D object. If a Histogram of the given name does not exist it creates a new ICloud1D and returns that.
         // 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(in the API reference documentation) 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(in the API reference documentation), 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(in the API reference documentation). 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.

More Information

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.