AIDA Users Guide

After a brief introduction to AIDA, its purpose and its philosophy, we present examples showing how to use each major component of the AIDA toolkit.

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.createHistogram1D("test 1d",50,-3,3);
      IHistogram2D h2d = hf.createHistogram2D("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.region(0).plot(h1d);
      plotter.region(1).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, clouds and profile histograms (IHistogramFactory), 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:

Histogram Arithmetic

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.createHistogram1D("test 1d",50,-3,6);
      IHistogram1D h2 = hf.createHistogram1D("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.subtract("h1-h2",h1,h2);
      IHistogram1D mul = hf.multiply("h1*h2",h1,h2);
      IHistogram1D div = hf.divide("h1 over h2",h1,h2);
      
      IPlotter plotter = af.createPlotterFactory().create("Plot");
      plotter.createRegions(2,2,0);
      plotter.region(0).plot(plus);
      plotter.region(1).plot(minus);
      plotter.region(2).plot(mul);
      plotter.region(3).plot(div);
      plotter.show();
   }
}

Profiles

AIDA supports 1D and 2D profiles.  IProfiles are created throught the IHistogramFactory that also supports arithmetic operations like sum, subtraction, multiplication, division and weighted mean. As for IHistograms, the IProfiles involved in the arithmetic operations must have the same binning and will be unchanged by the operations itself.

Create an IProfile

As for IHistograms it is possible to create IProfiles with fixed or variable bin width; the example below shows how to create them.

import hep.aida.*;

public class ProfileCreate
{
   public static void main(String[] argv)
   {    
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      // Create 1D and 2D IProfile with fixed bin width
      IProfile1D prof1DFixedBinWidth = hf.createProfile1D("prof1DFixedBinWidth","Fixed bin width 1D", 10, 0, 1);
      IProfile2D prof2DFixedBinWidth = hf.createProfile2D("prof2DFixedBinWidth","Fixed bin width 2D", 10, 0, 1, 10, -5, 5);

      double[] xBinEdges = {0,0.1,0.21,0.35,0.48,0.52,0.65,0.75,0.83,0.94,1.0};
      double[] yBinEdges = {-5.0,-4.1,-3.2,-2.0,-1.1,-0.4,1.2,2.3,3.5,4.2,5.0};

      // Create 1D and 2D IProfile with variable bin width
      IProfile1D prof1DVariableBinWidth = hf.createProfile1D("prof1DVariableBinWidth", "Variable bin width 1D", xBinEdges);
      IProfile2D prof2DVariableBinWidth = hf.createProfile2D("prof2DVariableBinWidth", "Variable bin width 2D", xBinEdges, yBinEdges);

   }
}

Fill an IProfile

To fill an IProfile invoke the fill method. In the example below we fill the IProfiles created in the previous example.

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

public class ProfileFill
{
   public static void main(String[] argv)
   {    
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      // Create 1D and 2D IProfile with fixed bin width
      IProfile1D prof1DFixedBinWidth = hf.createProfile1D("prof1DFixedBinWidth","Fixed bin width 1D", 10, 0, 1);
      IProfile2D prof2DFixedBinWidth = hf.createProfile2D("prof2DFixedBinWidth","Fixed bin width 2D", 10, 0, 1, 10, -5, 5);

      double[] xBinEdges = {0,0.1,0.21,0.35,0.48,0.52,0.65,0.75,0.83,0.94,1.0};
      double[] yBinEdges = {-5.0,-4.1,-3.2,-2.0,-1.1,-0.4,1.2,2.3,3.5,4.2,5.0};

      // Create 1D and 2D IProfile with variable bin width
      IProfile1D prof1DVariableBinWidth = hf.createProfile1D("prof1DVariableBinWidth", "Variable bin width 1D", xBinEdges);
      IProfile2D prof2DVariableBinWidth = hf.createProfile2D("prof2DVariableBinWidth", "Variable bin width 2D", xBinEdges, yBinEdges);

      Random r = new Random();

      for ( int i = 0; i < 100; i++ ) {
        double x = r.nextDouble();
        double y = x + 0.1*r.nextGaussian();

        // Fill the IProfiles with default weight.
        prof1DFixedBinWidth.fill(x,y);
        prof2DFixedBinWidth.fill(x,y, r.nextDouble());

        prof1DVariableBinWidth.fill(x,y);
        prof2DVariableBinWidth.fill(x,y, r.nextDouble());
      }

   }
}

Fit and Plot an IProfile

In the example below we show how to fit and display an IProfile.

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

public class ProfileFitAndPlot
{
   public static void main(String[] argv)
   {    
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      // Create 1D and 2D IProfile with fixed bin width
      IProfile1D prof1DFixedBinWidth = hf.createProfile1D("prof1DFixedBinWidth","Fixed bin width 1D", 10, 0, 1);
      IProfile2D prof2DFixedBinWidth = hf.createProfile2D("prof2DFixedBinWidth","Fixed bin width 2D", 10, 0, 1, 10, -5, 5);

      double[] xBinEdges = {0,0.1,0.21,0.35,0.48,0.52,0.65,0.75,0.83,0.94,1.0};
      double[] yBinEdges = {-5.0,-4.1,-3.2,-2.0,-1.1,-0.4,1.2,2.3,3.5,4.2,5.0};

      // Create 1D and 2D IProfile with variable bin width
      IProfile1D prof1DVariableBinWidth = hf.createProfile1D("prof1DVariableBinWidth", "Variable bin width 1D", xBinEdges);
      IProfile2D prof2DVariableBinWidth = hf.createProfile2D("prof2DVariableBinWidth", "Variable bin width 2D", xBinEdges, yBinEdges);

      Random r = new Random();

      for ( int i = 0; i < 100; i++ ) {
        double x = r.nextDouble();
        double y = x + 0.1*r.nextGaussian();

        // Fill the IProfiles with default weight.
        prof1DFixedBinWidth.fill(x,y);
        prof2DFixedBinWidth.fill(x,y, r.nextDouble());

        prof1DVariableBinWidth.fill(x,y);
        prof2DVariableBinWidth.fill(x,y, r.nextDouble());
      }

      // Create the Fitter and fit the profiles
      IFitFactory  fitFactory = af.createFitFactory();
      IFitter      fitter     = fitFactory.createFitter("Chi2","minuit");

      // Perform the fits
      IFitResult resProf1DFix = fitter.fit(prof1DFixedBinWidth,"p1");

      IFitResult resProf1DVar = fitter.fit(prof1DVariableBinWidth,"p1");

      // Display the results
      IPlotter plotter = af.createPlotterFactory().create("Fit and Plot an IProfile");
      plotter.createRegions(2,1);
      plotter.region(0).plot( prof1DFixedBinWidth );
      plotter.region(0).plot( resProf1DFix.fittedFunction() );
      plotter.region(1).plot( prof1DVariableBinWidth );
      plotter.region(1).plot( resProf1DVar.fittedFunction() );
      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 IHistogramFactory 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();
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      ICloud1D cl1D = hf.createCloud1D( "cl1D" );
      ICloud2D cl2D = hf.createCloud2D( "cl2D", "2-Dimensional Cloud" );
      ICloud3D cl3D = hf.createCloud3D( "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();
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      ICloud1D cl1D = hf.createCloud1D( "cl1D", "1-Dimensional Cloud", 1500, "" );
      ICloud2D cl2D = hf.createCloud2D( "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.region(0).plot(cl1DHist);
      plotter.region(1).plot(cl2D);
      plotter.show();     
   }
}

DataPointSets

An IDataPointSet is a collection of IDataPoints. Each IDataPoint is an n-dimensional collection of IMeasurements. Through an IDataPointSetFactory it is possible to either create empty IDataPointSets or already full sets using the data stored in IHistograms, IClouds and IProfiles. IDataPoints and IMeasurements cannot be created, they can only be accessed through the IDataPointSet.

AIDA also provides arithmetic operations among IDataPointSets that have the same size and the same dimension.

Create and Fill an IDataPointSet

In the example below we show how to create an empty one and two dimensional IDataPointSet, how to fill it and plot it:

import hep.aida.*;

public class DataPointSetCreateAndFill
{
   public static void main(String[] argv)
   {    
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create();
      IDataPointSetFactory dpsf = af.createDataPointSetFactory(tree);
      
      // Create a one dimensional IDataPointSet.
      IDataPointSet dps1D = dpsf.create("dps1D","one dimensional IDataPointSet",1);

      // Fill the one dimensional IDataPointSet
      double[] yVals1D = { 0.32, 0.45, 0.36, 0.29, 0.34 };
      double[] yErrP1D = { 0.06, 0.07, 0.03, 0.07, 0.04 };

      for ( int i = 0; i<yVals1D.length; i++ ) {
        dps1D.addPoint();
        dps1D.point(i).coordinate(0).setValue( yVals1D[i] );
        dps1D.point(i).coordinate(0).setErrorPlus( yErrP1D[i] );
      }


      // Create a two dimensional IDataPointSet.
      IDataPointSet dps2D = dpsf.create("dps2D","two dimensional IDataPointSet",2);

      // Fill the two dimensional IDataPointSet
      double[] yVals2D = { 0.12, 0.22, 0.35, 0.42, 0.54 , 0.61 };
      double[] yErrP2D = { 0.01, 0.02, 0.03, 0.03, 0.04 , 0.04 };
      double[] yErrM2D = { 0.02, 0.02, 0.02, 0.04, 0.06 , 0.05 };
      double[] xVals2D = { 1.5, 2.6, 3.4, 4.6, 5.5 , 6.4 };
      double[] xErrP2D = { 0.5, 0.5, 0.4, 0.4, 0.5 , 0.5 };

      for ( int i = 0; i<yVals2D.length; i++ ) {
        dps2D.addPoint();
        dps2D.point(i).coordinate(0).setValue( xVals2D[i] );
        dps2D.point(i).coordinate(0).setErrorPlus( xErrP2D[i] );
        dps2D.point(i).coordinate(1).setValue( yVals2D[i] );
        dps2D.point(i).coordinate(1).setErrorPlus( yErrP2D[i] );
        dps2D.point(i).coordinate(1).setErrorMinus( yErrM2D[i] );
      }

      // Display the results
      IPlotter plotter = af.createPlotterFactory().create("Plot IDataPointSets");
      plotter.createRegions(2,1);
      plotter.region(0).plot( dps1D );
      plotter.region(1).plot( dps2D );
      plotter.show();


   }
}

Create, Fill and Fit an IDataPointSet

In the example below we show how to fit a two dimensional IDataPointSet, with a one dimensional, second order polynomial

import hep.aida.*;

public class CreateAndFitDataPointSet {

   public static void main(String[] argv) {    

      IAnalysisFactory     af     = IAnalysisFactory.create();
      ITree                tree   = af.createTreeFactory().create();
      IDataPointSetFactory dpsf   = af.createDataPointSetFactory(tree);
      IFunctionFactory     funcF  = af.createFunctionFactory(tree);
      IFitFactory          fitF   = af.createFitFactory();
      IFitter              fitter = fitF.createFitter("Chi2","uncmin");

      // Create a two dimensional IDataPointSet.
      IDataPointSet dataPointSet = dpsf.create("dataPointSet","two dimensional IDataPointSet",2);

      // Fill the two dimensional IDataPointSet
      double[] yVals2D = { 0.12, 0.22, 0.35, 0.42, 0.54 , 0.61 };
      double[] yErrP2D = { 0.01, 0.02, 0.03, 0.03, 0.04 , 0.04 };
      double[] yErrM2D = { 0.02, 0.02, 0.02, 0.04, 0.06 , 0.05 };
      double[] xVals2D = { 1.5, 2.6, 3.4, 4.6, 5.5 , 6.4 };
      double[] xErrP2D = { 0.5, 0.5, 0.4, 0.4, 0.5 , 0.5 };

      for ( int i = 0; i<yVals2D.length; i++ ) {
        dataPointSet.addPoint();
        dataPointSet.point(i).coordinate(0).setValue( xVals2D[i] );
        dataPointSet.point(i).coordinate(0).setErrorPlus( xErrP2D[i] );
        dataPointSet.point(i).coordinate(1).setValue( yVals2D[i] );
        dataPointSet.point(i).coordinate(1).setErrorPlus( yErrP2D[i] );
        dataPointSet.point(i).coordinate(1).setErrorMinus( yErrM2D[i] );
      }


      //Create a 1d second order polynomial
      IFunction p2 = funcF.createFunctionFromScript("p2", 1, "a+b*x[0]+c*x[0]*x[0]", "a,b,c","",null); 

      IFitData data = fitF.createFitData();
      data.create1DConnection(dataPointSet,0,1);

      IFitResult fittedFunction = fitter.fit(data,p2);

      // Display the results
      IPlotter plotter = af.createPlotterFactory().create("Plot IDataPointSets");
      plotter.createRegions();
      plotter.region(0).plot( dataPointSet );
      plotter.region(0).plot( fittedFunction.fittedFunction() );
      plotter.show();


   }
}







Create an IDataPointSet from another AIDA data source

Through the IDataPointSetFactory it is easy to convert an IHistogram, an ICloud or an IProfile to an IDataPointSet as shown in the example below:

import hep.aida.*;

public class DataPointSetCreateFromData
{
   public static void main(String[] argv) throws java.io.IOException
   {    
      IAnalysisFactory af = IAnalysisFactory.create();

      // Create a tree loading the AIDA objects stored in an AIDA file.
      ITree tree = af.createTreeFactory().create("aidaStore.aida");

      IDataPointSetFactory dpsf = af.createDataPointSetFactory(tree);

      IHistogram1D h1 = (IHistogram1D) tree.find("h1");
      IProfile2D   p2 = (IProfile2D)   tree.find("p2");
      ICloud3D     c3 = (ICloud3D)     tree.find("c3");
        
      // Create IDataPointSets from the the above AIDA objects.
      IDataPointSet dps1DFromHist   = dpsf.create("dps1DFromHist",h1);
      IDataPointSet dps2DFromProf   = dpsf.create("dps2DFromProf",p2);
      IDataPointSet dps3DFromCloud  = dpsf.create("dps2DFromCloud",c3);
   }
}

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.,"+
      "px = 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,tuple.getTuple(3).columnMin(0),tuple.getTuple(3).columnMax(0));
    
    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.

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.createHistogram1D("test 1d",50,-3,3);
      hf.createHistogram2D("test 2d",50,-3,3,50,-3,3);
      
      tree.mkdir("/folder1");
      tree.cd("/folder1");
      hf.createHistogram1D("test 1d",50,-3,3);
      hf.createHistogram2D("test 2d",50,-3,3,50,-3,3);   
      
      tree.mkdir("/folder2");
      tree.cd("/folder2");
      hf.createHistogram1D("test 1d",50,-3,3);
      hf.createHistogram2D("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","xml",false,true);
      IHistogramFactory hf = af.createHistogramFactory(tree);
      
      IHistogram1D h1d = hf.createHistogram1D("test 1d",50,-3,3);
      IHistogram2D h2d = hf.createHistogram2D("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.

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

public class Restore 
{
   public static void main(String[] argv) throws IOException
   {
      IAnalysisFactory af = IAnalysisFactory.create();
      ITree tree = af.createTreeFactory().create("myFile.aida","xml");
      
      IHistogram1D h1d = (IHistogram1D) tree.find("test 1d");
      IHistogram2D h2d = (IHistogram2D) tree.find("test 2d");
      
      IPlotter plotter = af.createPlotterFactory().create("Test");
      plotter.createRegions(2,1);
      plotter.region(0).plot(h1d);
      plotter.region(1).plot(h2d);
      plotter.show();
   }
}

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.createHistogram2D("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.destroyRegions();
      plotter.createRegion(0,0,.66,1).plot(h2d);
      plotter.createRegion(.66,0,.33,.5).plot(hf.projectionX("X Projection",h2d));
      plotter.createRegion(.66,.5,.33,.5).plot(hf.projectionY("Y Projection",h2d));
      plotter.show();
   }
}

Functions

The following example shows how to create a simple function and use it to do a simple fit to a histogram:

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);
      IFitFactory fitFactory = analysisFactory.createFitFactory();
      
      // Create 1D histogram
      IHistogram1D h1d = histogramFactory.createHistogram1D("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
      IFunction f = functionFactory.createFunctionByName("Gaussian", "G");
      
      // Do Fit
      IFitter fitter = fitFactory.createFitter("chi2");
      IFitResult result = fitter.fit(h1d,f);
      
      // Show results
      plotter.createRegions(1,1,0);
      plotter.region(0).plot(h1d);
      plotter.region(0).plot(f);
      plotter.show();
   }
}

Fitter

The AIDA IFitter interface provides the user the possibility to fit IFunctions to any AIDA data storage object. Binned fits can be perfomed on IHistograms, IProfiles and IDataPointSets, while unbinned fits can be performed on IClouds and ITuples. Simple fits can be perfomed directely on the data storage objects while the IFitData interface is to be used for a greater control over the data, in particular its ranges and the connection to the IFunction's variables. Through the IFitter it is also possible to change the underlying optimization engine as well as the fit method used.

Chi2 Fit to an IHistogram

A simple chi2 fit to an histogram is perfomed in the example below:

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

public class Chi2FitToHistogram
{
   public static void main(String[] args)
   {
      // Create factories
      IAnalysisFactory analysisFactory = IAnalysisFactory.create();
      IHistogramFactory histogramFactory = analysisFactory.createHistogramFactory(analysisFactory.createTreeFactory().create());
      IPlotter plotter = analysisFactory.createPlotterFactory().create("Plot");
      IFitFactory fitFactory = analysisFactory.createFitFactory();
      
      // Create 1D histogram
      IHistogram1D h1d = histogramFactory.createHistogram1D("Gaussian Distribution",100,-5,5);
      
      // Fill 1D histogram with Gaussian
      Random r = new Random();
      for (int i=0; i<5000; i++)
         h1d.fill(r.nextGaussian());
      
      // Do Fit
      IFitter fitter = fitFactory.createFitter("chi2");
      IFitResult result = fitter.fit(h1d,"g");
      
      // Show results
      plotter.createRegions(1,1,0);
      plotter.destroyRegions();
      plotter.region(0).plot(h1d);
      plotter.region(0).plot(result.fittedFunction());
      plotter.show();
   }
}

Simple Binned and Unbinned Fits

In the example below it is shown how to perfom a binned and an unbinned fit over the same data using different optimizers and fit methods.

In the JAIDA implementation there are currently two optimizers available: Minuit and Uncmin and it is possible to choose among the following fit methods: ChiSquared, CleverChiSquared, BinnedMaximumLikelihood, LeastSquares, UnbinnedMaximumLikelihood.

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

public class SimpleFit
{
  public static void main(String[] argv) throws java.io.IOException
  {
    
    IAnalysisFactory  anFactory   = IAnalysisFactory.create();
    ITree             tree        = anFactory.createTreeFactory().create("storeForFittingExample");
    IHistogramFactory histFactory = anFactory.createHistogramFactory( tree );
    ITupleFactory     tuplFactory = anFactory.createTupleFactory( tree );
    IFunctionFactory  funcFactory = anFactory.createFunctionFactory( tree );
    IFitFactory       fitFactory  = anFactory.createFitFactory();
    IFitter           fitter      = fitFactory.createFitter("Chi2","minuit");
    
    IHistogram1D gaussHist  = histFactory.createHistogram1D("gaussHist","Gaussian Histogram",100,-5,5);
    ICloud1D     gaussCloud = histFactory.createCloud1D("gaussCloud","Gaussian Cloud");
    ITuple       tuple      = tuplFactory.create("tuple","Tuple Example","double gaussDistr");

    Random r = new Random();
    for (int i=0; i<10000; i++) {
      double x = r.nextGaussian();
      gaussHist.fill(x);
      gaussCloud.fill(x);
      tuple.fill(0,x);
      tuple.addRow();
    }

    // Chi2 fit with Minuit
    IFitResult minuitChi2Fit = fitter.fit(gaussHist,"g");
    
    // Least Squares fit with Minuit
    fitter.setFitMethod("LS");
    IFitResult minuitLeastSquaresFit = fitter.fit(gaussHist,"g");      

    // Binned Maximum Likelihood fit with Minuit
    fitter.setFitMethod("binnedMaximumLikelihood");
    IFitResult minuitBinnedMaxLikelihoodFit = fitter.fit(gaussHist,"g"); 

    // Unbinned Maximum Likelihood fit with Uncmin
    fitter.setEngine("uncmin");
    fitter.setFitMethod("uml");
    IFitResult uncminUMLFitToCloud = fitter.fit(gaussCloud,"g");

    String[] gaussColumn = {"gaussDistr"};
    IFitData fitData = fitFactory.createFitData();
    fitData.createConnection(tuple,gaussColumn);

    IFitResult uncminUMLFitToTuple = fitter.fit(fitData,"g");


    IHistogram1D gaussProj  = histFactory.createHistogram1D("gaussProj","Gaussian Histogram Projected from ITuple",100,-5,5);
    tuple.project( gaussProj, tuplFactory.createEvaluator("gaussDistr") );
    IPlotter plotter = anFactory.createPlotterFactory().create("Plot");
    plotter.createRegion(0,0,.66,1).plot(gaussHist);
    plotter.destroyRegions();
    plotter.createRegion(0,0,.66,1).plot(gaussHist);
    plotter.region(0).plot( minuitChi2Fit.fittedFunction() );
    plotter.region(0).plot( minuitLeastSquaresFit.fittedFunction() );
    plotter.region(0).plot( minuitBinnedMaxLikelihoodFit.fittedFunction() );
    
    gaussCloud.convert(100,gaussCloud.lowerEdge(),gaussCloud.upperEdge());
    plotter.createRegion(.66,0,.33,.5).plot(gaussCloud.histogram());
    
    IModelFunction cloudFunc = (IModelFunction)uncminUMLFitToCloud.fittedFunction();
    cloudFunc.normalize(false);
    double gaussCloudNorm = gaussCloud.entries()*( gaussCloud.upperEdge()-gaussCloud.lowerEdge() )/gaussCloud.histogram().axis().bins();
    double cloudFuncNorm = gaussCloudNorm/(Math.sqrt(2*Math.PI)*cloudFunc.parameter("sigma"));
    cloudFunc.setParameter("amplitude",cloudFuncNorm);
    plotter.region(1).plot( cloudFunc );

    plotter.createRegion(.66,.5,.33,.5).plot( gaussProj );


    IModelFunction tupleFunc = (IModelFunction)uncminUMLFitToTuple.fittedFunction();
    tupleFunc.normalize(false);
    
    double gaussProjNorm = gaussProj.entries()*( gaussProj.axis().upperEdge()-gaussProj.axis().lowerEdge() )/gaussProj.axis().bins();
    double tupleFuncNorm = gaussProjNorm/(Math.sqrt(2*Math.PI)*tupleFunc.parameter("sigma"));

    tupleFunc.setParameter("amplitude",tupleFuncNorm);
    plotter.region(2).plot( tupleFunc );
    plotter.show();
  }
}

Control fit parameters and set constraints

With the IFitter interface it is possible to have a more direct control over the fit: the parameters in the fit can be controlled with the IFitParameterSettings interface and it is also possible to set constraints among them. In the example below we create a scripted function an show how to control its parameters:

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

public class ComplexFit
{
  public static void main(String[] argv) throws java.io.IOException
  {
    
    IAnalysisFactory  anFactory   = IAnalysisFactory.create();
    ITree             tree        = anFactory.createTreeFactory().create("storeForFittingExample");
    IHistogramFactory histFactory = anFactory.createHistogramFactory( tree );
    ITupleFactory     tuplFactory = anFactory.createTupleFactory( tree );
    IFunctionFactory  funcFactory = anFactory.createFunctionFactory( tree );
    IFitFactory       fitFactory  = anFactory.createFitFactory();
    IFitter           fitter      = fitFactory.createFitter("Chi2","minuit");
    
    IHistogram2D hist  = histFactory.createHistogram2D("hist","Test Histogram",100,-5,15,50,-5,5);

    Random r = new Random();

    for (int i=0; i<10000; i++) {
      double x = r.nextGaussian()+5;
      if ( r.nextDouble() > 0.8 ) x = 2.5*r.nextGaussian()+5;
      double y = r.nextGaussian();
      hist.fill(x,y);
    }
    
    IFitData fitData = fitFactory.createFitData();
    fitData.create2DConnection(hist);

    IFunction func = funcFactory.createFunctionFromScript("twoDdistr",2,"N*(a*exp( -(x[0]-mu0)*(x[0]-mu0)/(2*s0*s0) )+"
                       +"(1-a)*exp( -(x[0]-mu1)*(x[0]-mu1)/(2*s1*s1) ))*exp( -(x[1]-mu2)*"
                       +"(x[1]-mu2)/(2*s2*s2) )","N,a,mu0,s0,mu1,s1,mu2,s2","",null);


    double[] initialPars = { 1, 0.8, 5, 1, 5, 2, 0, 1};
    func.setParameters( initialPars );

    fitter.fitParameterSettings("mu2").setFixed(true);
    fitter.fitParameterSettings("a").setBounds(0.5,0.9);
    fitter.fitParameterSettings("a").setStepSize(0.001);
    fitter.fitParameterSettings("s1").setBounds(2,4);
    fitter.fitParameterSettings("s1").setStepSize(0.1);
    fitter.setConstraint("s0 = s2");
    fitter.setConstraint("mu0 = mu1");


    IFitResult fitResult = fitter.fit(fitData,func);

    System.out.println("Chi2 = "+fitResult.quality());
    
    double[] fPars     = fitResult.fittedParameters();
    double[] fParErrs  = fitResult.errors();
    String[] fParNames = fitResult.fittedParameterNames();

    for(int i=0; i< fitResult.fittedFunction().numberOfParameters(); i++ ) 
      System.out.println(fParNames[i]+" : "+fPars[i]+" +- "+fParErrs[i]);


    IPlotter plotter = anFactory.createPlotterFactory().create("Plot");
    plotter.destroyRegions();
    plotter.createRegion(0,0,.66,1).plot(hist);
    plotter.createRegion(.66,0,.33,.5).plot( histFactory.projectionX("projX",hist) );
    plotter.createRegion(.66,.5,.33,.5).plot( histFactory.projectionY("projY",hist) );
    plotter.show();

  }
}

Scans and contours

Scans and contours can be obtained as shown below:

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

public class ScanAndContour
{       
  public static void main(String[] argv) throws java.io.IOException
  {        
    IAnalysisFactory  anFactory   = IAnalysisFactory.create();
    ITree             tree        = anFactory.createTreeFactory().create("storeForFittingExample");
    IHistogramFactory histFactory = anFactory.createHistogramFactory( tree );
    ITupleFactory     tuplFactory = anFactory.createTupleFactory( tree );
    IFunctionFactory  funcFactory = anFactory.createFunctionFactory( tree );
    IFitFactory       fitFactory  = anFactory.createFitFactory();
    IFitter           fitter      = fitFactory.createFitter("Chi2","minuit");

    IHistogram1D hist  = histFactory.createHistogram1D("hist","Test Histogram",100,-5,5);

    Random r = new Random();

    for (int i=0; i<10000; i++) {
      double x = r.nextGaussian();
      hist.fill(x);
    }

   IFitData fitData = fitFactory.createFitData();
   fitData.create1DConnection(hist);

   IFitResult fitResult = fitter.fit(fitData,"g");

   int meanIndex  = fitResult.fittedFunction().indexOfParameter("mean");
   double meanVal = fitResult.fittedParameters()[meanIndex];
   double meanErr = fitResult.errors()[meanIndex];
   IDataPointSet meanScan = fitter.createScan1D(fitData, fitResult.fittedFunction(),"mean",20, meanVal-3*meanErr, meanVal+3*meanErr);

   int sigmaIndex  = fitResult.fittedFunction().indexOfParameter("sigma");
   double sigmaVal = fitResult.fittedParameters()[sigmaIndex];
   double sigmaErr = fitResult.errors()[sigmaIndex];
   IDataPointSet oneSigmaContour = fitter.createContour(fitData, fitResult, "mean", "sigma", 10, 1);
   IDataPointSet twoSigmaContour = fitter.createContour(fitData, fitResult, "mean", "sigma", 10, 2);

   IPlotter plotter = anFactory.createPlotterFactory().create("Plot");
   plotter.destroyRegions();
   plotter.createRegion(0,0,.66,1).plot(hist);
   plotter.region(0).plot(fitResult.fittedFunction());
   plotter.createRegion(.66,0,.33,.5).plot( meanScan );
   plotter.createRegion(.66,.5,.33,.5).plot( twoSigmaContour );
   plotter.region(2).plot( oneSigmaContour );
   plotter.show();

  }
}