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.createHistogram1D("h1dI",50,tuple.columnMin(colI),tuple.columnMax(colI));
      IHistogram1D h1dF = hf.createHistogram1D("h1dF",50,tuple.columnMin(colF),tuple.columnMax(colF));
      IHistogram1D h1dG = hf.createHistogram1D("h1dG",50,tuple.columnMin(colG),tuple.columnMax(colG));
      IHistogram2D h2d = hf.createHistogram2D("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.region(0).plot(h1dI);
      plotter.region(1).plot(h1dF);
      plotter.region(2).plot(h1dG);
      plotter.region(3).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.

Use of IFilters and IEvaluators

IFilter and IEvaluator are simple objects that can be created by ITupleFactory and help manage data in an ITuple. Corresponding "create" methods in the factory take String that can contain ITuple column names, standard arithmetical and boolean operators (like +, -, /, *, > , <, ==, ...) and standard functions from the java.lang.Math class ( sin, exp, pow, ...). The string should evaluate to boolean for IFilter and to double for IEvaluator.

Example below demonstrates how to use IFilter and IEvaluator to filter and evaluate ITuple data on a row-by-row basis (1) and how to fill histograms from an ITuple (2).

Note: IFilters and IEvaluators are created as a stand-alone objects. You must associate them with ITuple with initialize(ITuple tuple) method before you can use them.

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

public class FilterAndEvaluatorExample
{
   public static void main(String[] argv)
   {
        IAnalysisFactory af = IAnalysisFactory.create();
        ITree tree = af.createTreeFactory().create();
        ITupleFactory tf = af.createTupleFactory( tree );
        IHistogramFactory hf = af.createHistogramFactory(tree);

        java.util.Random r = new java.util.Random();

        ITuple tuple = tf.create("TupleTreeName","Title: Test Tuple", "int n, double x, double y, double z");

        for ( int i = 0; i < 30; i++ ) {
            double v1 = r.nextDouble()*10.;
            double v2 = r.nextDouble()*10.;
            double v3 = 5.3*v1+2.1*v1*v2 + 10.7;
            tuple.fill(0,i);
            tuple.fill(1,v1);
            tuple.fill(2,v2);
            tuple.fill(3,v3);
            tuple.addRow();
        }

        // Create IFilter and initialize it to this ITuple
        IFilter filter = tf.createFilter("5.3*x+2.1*y*x + 10.7 > 50.");
        filter.initialize(tuple);

        // Create IEvaluator and initialize it to this ITuple
        IEvaluator evaluator = tf.createEvaluator("(1.5*x*x-5.2*y*x + 4*sin(y))/85");
        evaluator.initialize(tuple);

        // Example 1: Filter ITuple Data
        tuple.start();
        while (tuple.next()) {
            if (filter.accept()) {
                System.out.println(tuple.getInt(0) + "\t Row passed, evaluate: " + evaluator.evaluateDouble());
            } else {
                System.out.println(tuple.getInt(0) + "\t Row failed, do not evaluate");
            }                            
        }

        // Use IHistogramFactory to create two empty histograms
        IHistogram1D h1 = hf.createHistogram1D("hist-1", "Use All Data", 50, -10, 10);
        IHistogram1D h2 = hf.createHistogram1D("hist-2", "Use Filtered Data", 50, -10, 10);
 
        // Example 2: Fill histograms from ITuple
        tuple.project(h1, evaluator);
        tuple.project(h2, evaluator, filter);

        // Plot histograms
        IPlotter plotter = af.createPlotterFactory().create("Filter and Evaluator Example");
        plotter.createRegions(2,1,0);

        plotter.region(0).plot(h1);
        plotter.region(1).plot(h2);
        plotter.show();
   }
}

Create Chained and Filtered ITuples

ITupleFactory has several methods to group ITuples together and to create ITuple with a reduced data set.

createChained methods create a logical chain of ITuples. All ITuples in the set must have the same structure and resulting chained ITuple can not be filled. In a sense, chained ITuple is just a view of original Ituples, so no data is copied during creation of chained ITuple.

createFiltered method creates a new reduced tuple (less rows) from an existing one by applying a filter. Data is explicitly copied to a new n-tuple. User also has ability to copy only selected subset of columns by providing array with column names

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

public class ChainedAndFilteredTuplesExample
{
   public static void main(String[] argv)
   {
        IAnalysisFactory af = IAnalysisFactory.create();    
        ITree tree = af.createTreeFactory().create();
        ITupleFactory tf = af.createTupleFactory( tree );

        java.util.Random r = new java.util.Random();
        
        // Create and fill 4 different ITuples
        ITuple tup1 = tf.create("tup1","tup1","int n, double x");
        ITuple tup2 = tf.create("tup2","tup2","int n, double x");
        ITuple tup3 = tf.create("tup3","tup3","int n, double x");
        ITuple tup4 = tf.create("tup4","tup4","int n, double x");
        
        for ( int i = 0; i < 20; i++ ) {
            tup1.fill(0,i);
            tup2.fill(0,i+20);
            tup3.fill(0,i+40);
            tup4.fill(0,i+60);

            tup1.fill(1, r.nextDouble()*10.);
            tup2.fill(1, r.nextDouble()*10.);
            tup3.fill(1, r.nextDouble()*10.);
            tup4.fill(1, r.nextDouble()*10.);

            tup1.addRow();
            tup2.addRow();
            tup3.addRow();
            tup4.addRow();
        }

        // Create a chain
        ITuple[] set = new ITuple[] { tup1, tup2, tup3, tup4};
        ITuple chain = tf.createChained("ChainedTuple", "New Chained Tuple", set);

        chain.start();
        System.out.println("\n\nChained Tuple:");
        while (chain.next()) System.out.println(chain.getInt(0) + "\t" + chain.getDouble(1));


        // Create IFilter and filtered ITuple
        IFilter filter = tf.createFilter("n>14 && n<46");
        filter.initialize(chain);
        ITuple filteredTuple = tf.createFiltered("FilteredTuple", chain, filter);

        filteredTuple.start();
        System.out.println("\n\nFiltered Tuple:");
        while (filteredTuple.next()) System.out.println(filteredTuple.getInt(0) + 
                                                        "\t" + filteredTuple.getDouble(1));
   }
}

ITuple with complex structure.

Within AIDA it is possible to create ITuples containing columns of ITuples. This allows the user to create ITuples with complex structures. Here is an example of how to create, fill and retrieve data from such an ITuple:

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

public class createAndFillTupleWithComplexStructure {
  
  public static void main(String[] argv) throws java.io.IOException {
    
    String columnString = "int event =0,  tracks =0; ITuple momentums  = { double px = .2, py = 3.,"+
      "pz = 0., ITuple hits = {int x,y,z} }; float ipx, ipy, ipz";
    
    IAnalysisFactory analysisFactory = IAnalysisFactory.create();
    ITreeFactory treeFactory = analysisFactory.createTreeFactory();
    ITree tree = treeFactory.create("testTupleWithComplexStructure.aida","type=xml;compress=no");
    ITupleFactory tupleFactory = analysisFactory.createTupleFactory(tree);
    ITuple tuple = tupleFactory.create("tuple", "label",columnString,"");
    
    Random r = new Random();
    int events = 100;
    
    for ( int i=0; i<events; i++ ) {
      tuple.fill(0, i);
      
      int tracks = r.nextInt(10);
      tuple.fill(1,tracks);
      
      ITuple momentum = tuple.getTuple( 2 );
      
      for ( int j = 0; j<tracks; j++ ) {
        momentum.fill(0,r.nextGaussian());
        momentum.fill(1,r.nextGaussian());
        momentum.fill(2,r.nextGaussian());
        
        int nHits = r.nextInt(20);
        
        ITuple hits = momentum.getTuple( 3 );
        for ( int k = 0; k<nHits; k++ ) {
          hits.fill(0,r.nextInt(40));
          hits.fill(1,r.nextInt(40));
          hits.fill(2,r.nextInt(40));
          hits.addRow();
        } // end of hits loop
        momentum.addRow();
      }// end of tracks loop
      
      tuple.fill(3,r.nextGaussian());
      tuple.fill(4,r.nextGaussian());
      tuple.fill(5,r.nextGaussian());
      tuple.addRow();
    }//end of loop over events
    
    IHistogramFactory hf = analysisFactory.createHistogramFactory(tree);
    IHistogram1D pxHist = hf.createHistogram1D("pxHist",100,-5,5);
    
    tuple.start();
    while ( tuple.next() ) {
      ITuple momTuple = (ITuple) tuple.getObject(3);
      momTuple.start();
      
      while ( momTuple.next() ) 
        pxHist.fill( momTuple.getDouble(0) );
    }
    
    
    IPlotter plotter = analysisFactory.createPlotterFactory().create("Plot");
    plotter.createRegions(1,1,0);
    plotter.region(0).plot(pxHist);
    plotter.show();
    
  }
}


Notice the different ways of accessing the inner ITuple when filling and when retrieving the data. The getTuple(int index) method returns the ITuple ready to be filled, while the getObject(int index) method, invoked on the same column, returns the same ITuple but with the current row pointing to the current row of the higher level ITuple. For this reason the getObject(int index) method is used to retrieve the data. Also notice that the addRow() method has to be called for each of the individual inner ITuples evey time a row is ready to be stored.

Table of Contents -- Next Section


$Id: tuples.jsp,v 1.1 2006/03/09 18:22:10 turri Exp $