AIDA Users Guide

Contents

Introduction

What is AIDA?

AIDA is a standard set of interfaces for creating and manipulating histograms, n-tuples and related data analysis objects. It has been created cooperatively by a group of developers working on high-energy physics data analysis tools. The goal of the AIDA project is to provide the user with a powerful set of interfaces which can be used regardless of which analysis tool they are using. The advantages of this approach are that:

  1. The user will only need to learn one set of interfaces even if they use more than one tool.
  2. By pooling the experiences of several different development teams we will be able to develop a more complete solution to the data analysis problem.
  3. Different analysis tools built using AIDA will be able to interoperate, for example by exchanging objects in a common storage format (initially XML).

Currently two versions of the AIDA interfaces exist, one for Java and one for C++. The two interfaces are as identical as the underlying languages will permit.

We have been careful to avoid using a "lowest common denominator" approach in the development of the AIDA interfaces. Rather than limiting ourselves by the existing capabilities of the underlying analysis tools, we have designed a rich set of interfaces, with the expectation that the tool developers will need to add new features to support the full AIDA functionality. This does mean however that the early implementations of AIDA may not completely implement all features.

An Example AIDA Program

Before going into details, here is a trivial example program that uses the AIDA interfaces to create a 1D histogram, and display it.

import hep.aida.*;
import java.util.Random;

public class Histogram 
{
   public static void main(String[] argv)
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      IHistogramFactory hf = af.createHistogramFactory(af.createTreeFactory().create());
      
      IHistogram1D h1d = hf.create1D("test 1d",50,-3,3);
      IHistogram2D h2d = hf.create2D("test 2d",50,-3,3,50,-3,3);
      
      Random r = new Random();
      for (int i=0; i<10000; i++) 
      {
         h1d.fill(r.nextGaussian());
         h2d.fill(r.nextGaussian(),r.nextGaussian());
      }
      
      IPlotter plotter = af.createPlotterFactory().create("Plot");
      plotter.createRegions(1,2,0);
      plotter.plot(h1d);
      plotter.next();
      plotter.plot(h2d);
      plotter.show();
   }
}

A few things to notice in this example, first note that AIDA objects are always created from factories. Although different implementations of AIDA may return different objects from their factories, the returned objects will all implement the same standard AIDA interfaces. In this way it is possible to change from one AIDA implementation to another just by changing which IAnalysisFactory is used.

Overview of AIDA Classes

The rest of this document describes the key features that the AIDA user will need to know about:

Factories

In AIDA instead of creating objects directly using "new" one uses factories. There is one "master" factory, IAnalysisFactory from which other factories are obtained. The IAnalysisFactory allows you to obtain factories for creating trees (ITreeFactory), histograms (IHistogramFactory), clouds (ICloudFactory), tuples (ITupleFactory) etc.

You will see many examples of using factories in the remainder of this guide.

Histograms

AIDA supports 1D, 2D and 3D histograms.  Creating histograms is quite straightforward using the methods in IHistogramFactory.

Histograms support arithmetic operations, in particular add, subtract, multiply and divide. In all cases the operation is applied bin-by-bin, and the histograms involved in the operation must have the same binning. The input histograms are unchanged, and a new histogram is created as the result of the operation. All of the arithmetic operations are methods of IHistogramFactory to reflect the fact that a new histogram is always created as a result of the operation. For multi-dimensional histograms it is also possible to create slices and projections.

The following example illustrates using histograms:

import hep.aida.*;
import java.util.Random;

public class HistogramArithmetic 
{
   public static void main(String[] argv)
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      IHistogramFactory hf = af.createHistogramFactory(af.createTreeFactory().create());
      
      IHistogram1D h1 = hf.create1D("test 1d",50,-3,6);
      IHistogram1D h2 = hf.create1D("test 2d",50,-3,6);
      
      Random r = new Random();
      for (int i=0; i<10000; i++) 
      {
         h1.fill(r.nextGaussian());
         h2.fill(3+r.nextGaussian());
      }
      IHistogram1D plus = hf.add("h1+h2",h1,h2);
      IHistogram1D minus = hf.sub("h1-h2",h1,h2);
      IHistogram1D mul = hf.mul("h1*h2",h1,h2);
      IHistogram1D div = hf.div("h1/h2",h1,h2);
      
      IPlotter plotter = af.createPlotterFactory().create("Plot");
      plotter.createRegions(2,2,0);
      plotter.plot(plus);
      plotter.next();
      plotter.plot(minus);
      plotter.next();
      plotter.plot(mul);
      plotter.next();
      plotter.plot(div);
      plotter.show();
   }
}

Clouds

Clouds are one, two or three dimensional unbinned collections of data. They are used for scatter plots or dynamically rebinnable Histograms. A Cloud can be automatically converted to an Histogram when the number of entries exceeds a given threshold, or can be manually converted by the user.

Create an ICloud

IClouds are created through a ICloudFactory as shown in the example below:

import hep.aida.*;

public class CloudCreate
{
   public static void main(String[] argv)
   {    
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      ICloudFactory cf = af.createCloudFactory(tree);
      
      ICloud1D cl1D = cf.create1D( "cl1D" );
      ICloud2D cl2D = cf.create2D( "cl2D", "2-Dimensional Cloud" );
      ICloud3D cl3D = cf.create3D( "cl3D", "3-Dimensional Cloud", 1500, "autoConvert = false" );     
   }
}

In this example the IClouds cl1D and cl2D are set by default to autoconvert when the threshold is reached (Please note that in this case the threshold depends on the particular implementation of the AIDA package you are using). For the ICloud cl3D we set the threshold at 1500 events and we choose to switch off the autoConvert option; in this case to convert the ICloud it is necessary to invoke the convert method.

Filling an ICloud

In the example below we fill a 1-Dimensional and a 2-Dimensional Cloud with random numbers. For each entry we assign a random weight. We then plot the histograms produced by the Cloud auto-conversion

import hep.aida.*;
import java.util.Random;

public class Cloud
{   
   public static void main(String[] argv)
   {
      
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      ICloudFactory cf = af.createCloudFactory(tree);
      
      ICloud1D cl1D = cf.create1D( "cl1D", "1-Dimensional Cloud", 1500, "" );
      ICloud2D cl2D = cf.create2D( "cl2D", "2-Dimensional Cloud", 1500, "" );
      
      int entries = 20000;
      Random r = new Random();
      
      for ( int i = 0; i < entries; i++ )
      {
         double xval = r.nextGaussian();
         double yval = r.nextGaussian();
         double w    = r.nextDouble();
         
         cl1D.fill( xval, w );
         cl2D.fill( xval, yval, w );
      }
      
      IHistogram1D cl1DHist = cl1D.histogram();
      IHistogram2D cl2DHist = cl2D.histogram();
      
      IPlotter plotter = af.createPlotterFactory().create("Plot");
      plotter.createRegions(1,2,0);
      plotter.plot(cl1DHist);
      plotter.next();
      plotter.plot(cl2D);
      plotter.show();     
   }
}

Tuples

The AIDA ITuple interface provides a way to store and retrieve n-tuple data.

Create an ITuple

ITuples are created through a ITupleFactory by providing the name and the type of the columns within the Tuple; this can be done in two different ways:

import hep.aida.*;
import java.util.Random;

public class TupleCreate
{
   public static void main(String[] argv)
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      ITupleFactory tf = af.createTupleFactory(tree);
      
      String[] columnNames  =
      { "iFlat = 0", " fGauss = 3.", " fFlat =-2." };
      Class[] columnClasses =
      { Integer.TYPE, Float.TYPE, Float.TYPE };
      ITuple tuple1 = tf.create( "tuple1", "tupleLabel1", columnNames, columnClasses, "");
      
      String columnString = "int iFlat=0, float fGauss = 3.; fFlat=-2.";
      ITuple tuple2 = tf.create( "tuple2", "tupleLabel1", columnString, "");
   }
}

In the code above tuple1 is created by providing the factory two arrays specifying, respectively, the name and the type ( i.e. the Class ) of the Tuple's columns. Alternatively we create tuple2 by providing the ITupleFactory a single string with name and type for all the columns separated by either a coma (,) or by a semicolon (;). In both cases the default values are specified by following the column's name with = value . Please note that spaces are ignored.

There are all-together ten different types of columns: the eight primitive types ( int, short, long, float, double, char, boolean, byte ), String and Object.

Fill and retrieve data from an ITuple

An ITuple is filled by rows as shown below:

import hep.aida.*;
import java.util.Random;

public class Tuple
{
   public static void main(String[] argv)
   {
      
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      ITupleFactory tf = af.createTupleFactory(tree);
      
      String[] columnNames  = { "iFlat = 0", " fGauss = 3.", " fFlat =-2." };
      Class[] columnClasses = { Integer.TYPE, Float.TYPE, Float.TYPE };
      
      ITuple tuple = tf.create( "tuple", "tupleLabel", columnNames, columnClasses, "");
      
      Random r = new Random();
      for (int i=0; i<100000; i++)
      {
         tuple.fill(0, r.nextInt(20) );
         tuple.fill(1, (float)r.nextGaussian() );
         tuple.fill(2, r.nextFloat() );
         tuple.addRow();
      }
      
      int colG = tuple.findColumn("fGauss");
      int colF = tuple.findColumn("fFlat");
      int colI = tuple.findColumn("iFlat");
      
      IHistogramFactory hf = af.createHistogramFactory(tree);
      IHistogram1D h1dI = hf.create1D("h1dI",50,tuple.columnMin(colI),tuple.columnMax(colI));
      IHistogram1D h1dF = hf.create1D("h1dF",50,tuple.columnMin(colF),tuple.columnMax(colF));
      IHistogram1D h1dG = hf.create1D("h1dG",50,tuple.columnMin(colG),tuple.columnMax(colG));
      IHistogram2D h2d = hf.create2D("h2d",50,tuple.columnMin(colG),tuple.columnMax(colG),
      50,tuple.columnMin(colF),tuple.columnMax(colF));
      
      tuple.start();
      while ( tuple.next() )
      {
         h1dI.fill( tuple.getInt(colI) );
         h1dF.fill( tuple.getFloat(colF) );
         h1dG.fill( tuple.getFloat(colG) );
         h2d.fill( tuple.getFloat(colG), tuple.getFloat(colF) );
      }
      
      IPlotter plotter = af.createPlotterFactory().create("Plot");
      plotter.createRegions(2,2,0);
      plotter.plot(h1dI);
      plotter.next();
      plotter.plot(h1dF);
      plotter.next();
      plotter.plot(h1dG);
      plotter.next();
      plotter.plot(h2d);
      plotter.show();
   }
}

The addRow() method commits the row to storage. If the fill method has not been invoked for a given column when addRow() is reached, that column will be filled with its default value.

Please note that for each column type there is an appropriate get method.

IO and Trees

The AIDA ITree interface provide two capabilities. The ability to group analysis objects such as Histograms, Clouds, Tuples etc. into hierarchical directories (or folders), and the ability to save and restore sets of analysis objects into files or databases.

Directories

Here is an example of how to create a set of histograms in several different folders:

import hep.aida.*;
import java.util.Random;

public class Tree 
{
   public static void main(String[] argv)
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      hf.create1D("test 1d",50,-3,3);
      hf.create2D("test 2d",50,-3,3,50,-3,3);
      
      tree.mkdir("/folder1");
      tree.cd("/folder1");
      hf.create1D("test 1d",50,-3,3);
      hf.create2D("test 2d",50,-3,3,50,-3,3);   
      
      tree.mkdir("/folder2");
      tree.cd("/folder2");
      hf.create1D("test 1d",50,-3,3);
      hf.create2D("test 2d",50,-3,3,50,-3,3);         
   }
}

Each IHistogramFactory has an ITree associated with it. The ITree is set when the IHistogramFactory is created. Whenever the IHistogramFactory creates a new IHistogram it implicitly inserts it into the current directory of the associated ITree. The ITree initially contains a single folder (the "root folder"). New folders can be added using the mkdir(path) or mkdirs(path) method. You can change the current directory of the tree using the cd(path) method. All methods that take a path as an argument interpret that path using Unix conventions, so:

Trees also have methods for removing objects or directories, for locating objects within the tree, and for listing the contents of directories.

Storing and Retrieving Trees (and their contents)

A second use for trees is to allow objects to be stored and retrieved from files or databases. So far we have always used the ITreeFactory.create() method to create ITree's. This method creates an ITree that is not associated with any storage, so the objects associated with this type of Tree are only valid within the current process. The other methods of ITreeFactory allow ITree's to be associated with a file or database. The following example shows how to create a set of histograms and store them in a file.

import hep.aida.*;
import java.util.Random;
import java.io.IOException;

public class Store 
{
   public static void main(String[] argv) throws IOException
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create("myFile.aida","type=xml;compress=yes");
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      IHistogram1D h1d = hf.create1D("test 1d",50,-3,3);
      IHistogram2D h2d = hf.create2D("test 2d",50,-3,3,50,-3,3);
      
      Random r = new Random();
      for (int i=0; i<10000; i++) 
      {
         h1d.fill(r.nextGaussian());
         h2d.fill(r.nextGaussian(),r.nextGaussian());
      }
      
      tree.commit();
   }
}

In this case we are creating a compressed XML file. The precise types of files or databases which can be used will depend on which implementation of AIDA you are using, however all AIDA implementations should support reading and writing XML files to allow easy interchange of objects. The next example shows how to read an XML file back in.

Advanced Tree Capabilities

In designing the ITree interface we have borrowed some other concepts from Unix. In particular ITree's allow other ITree's to be mounted and unmounted at an arbitrary point in the tree. This allows a whole set of files to be opened but be viewed by the AIDA user as a single ITree. ITree's also support symbolic links.

Plotting

We have already seen simple use of plots the AIDA IPlotter interface. By default the plotter contains a single plotting region that covers the entire page, however any number of regions can be defined by the user. These regions may either consist of a regular grid created using the IPlotter.createRegions() method, or an arbitrary arrangement of regions created using the IPlotter.createRegion() method. At any time there is one currentRegion, which is the region that will be used when a new item is plotted. The Plotter allows histograms, clouds, and functions to be plotted. If more than one item is added to the same region the items will be overlaid on the same plot.

The following example shows how to use these methods:

import hep.aida.*;
import java.util.Random;

public class PlotExample
{
   public static void main(String[] argv)
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      IHistogramFactory hf = af.createHistogramFactory(af.createTreeFactory().create());
      
      IHistogram2D h2d = hf.create2D("test 2d",50,-30,30,50,-3,3);
      
      Random r = new Random();
      for (int i=0; i<10000; i++) 
      {
         h2d.fill(10*r.nextGaussian(),r.nextGaussian());
      }
      
      IPlotter plotter = af.createPlotterFactory().create("Plot");
      plotter.clearPage();
      plotter.createRegion(0,0,.66,1);
      plotter.plot(h2d);
      plotter.createRegion(.66,0,.33,.5);
      plotter.plot(hf.projectionX("X Projection",h2d));
      plotter.createRegion(.66,.5,.33,.5);
      plotter.plot(hf.projectionY("Y Projection",h2d));
      plotter.show();
   }
}

Functions and Fitting

The fitting interfaces in AIDA are not yet complete, and are likely to change significantly in future releases. It is possible however to perform and display simple fits, as shown by the following example:

import hep.aida.*;
import java.util.Random;

public class FitExample
{
   public static void main(String[] args)
   {
      // Create factories
      IAnalysisFactory analysisFactory = IAnalysisFactory.create();
      ITreeFactory treeFactory = analysisFactory.createTreeFactory();
      ITree tree = treeFactory.create();
      IPlotter plotter = analysisFactory.createPlotterFactory().create("Plot");
      IHistogramFactory histogramFactory = analysisFactory.createHistogramFactory(tree);
      IFunctionFactory functionFactory = analysisFactory.createFunctionFactory(tree);
      
      // Create 1D histogram
      IHistogram1D h1d = histogramFactory.create1D("Histogram 1D",50,-3,3);
      
      // Fill 1D histogram with Gaussian
      Random r = new Random();
      for (int i=0; i<5000; i++)
      {
         h1d.fill(r.nextGaussian());
      }
      
      // Create Gaussian fitting function
      IFitFunction f = functionFactory.createFit("Gaussian Fit", "Gaussian Fit", "G","amplitude=1., mean=0., sigma=1.");
      
      ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
      // Other supported functions:
      // f = functionFactory.createFit("Exp Fit", "Exponential Fit", "E", "amplitude= ; origin= ; exponent= ");
      // f = functionFactory.createFit("BW Fit", "Breit-Wigner Fit", "BW","amplitude= ; origin= ; width= ");
      // f = functionFactory.createFit("Poly Fit", "Polynomial Fit", "P", "a4= , a3= , a2= , a1= , a0= ");
      //////////////////////////////////////////////////////////////////////////////////////////////////////////////
      
      // Do Fit
      f.fit(h1d);
      
      // Show results
      plotter.createRegions(1,1,0);
      plotter.plot(h1d);
      plotter.plot(f);
      plotter.show();
   }
}


$Id: UsersGuide.html,v 1.2 2002/10/14 06:26:08 tonyj Exp $