]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
First version of kdtree (Alexander, Marian)
authormarian <marian@f7af4fe6-9843-0410-8265-dc069ae4e863>
Fri, 3 Aug 2007 10:07:45 +0000 (10:07 +0000)
committermarian <marian@f7af4fe6-9843-0410-8265-dc069ae4e863>
Fri, 3 Aug 2007 10:07:45 +0000 (10:07 +0000)
First version of PDF and interpolater (based on kdtree)

STAT/Makefile [new file with mode: 0644]
STAT/TKDInterpolator.cxx [new file with mode: 0644]
STAT/TKDInterpolator.h [new file with mode: 0644]
STAT/TKDSpline.cxx [new file with mode: 0644]
STAT/TKDSpline.h [new file with mode: 0644]
STAT/TKDTree.cxx [new file with mode: 0644]
STAT/TKDTree.h [new file with mode: 0644]
STAT/kdTreeLinkDef.h [new file with mode: 0644]

diff --git a/STAT/Makefile b/STAT/Makefile
new file mode 100644 (file)
index 0000000..24d9d20
--- /dev/null
@@ -0,0 +1,85 @@
+# AliRoot stat project
+# Makefile for main library - libKDTree.so
+#
+# Authors
+#       Marian Ivanov [M.Ivanov@gsi.de]
+#       Alexandru Bercuci [A.Bercuci@gsi.de]
+# Data     01.08.2007
+# version  0.0 [pre release]
+#
+
+SrcSuf    = cxx
+HdrSuf    = h
+ExeSuf    =
+ObjSuf    = o
+DllSuf    = so
+OutPutOpt = -o
+
+CXX       = g++
+LD        = g++
+CXXFLAGS  = -O -g -pg
+LDFLAGS   = -O -g -pg
+SOFLAGS   = -shared -g -pg
+
+ROOTCXX  = $(shell root-config --cflags)
+ROOTLIBS = $(shell root-config --libs) -lMinuit
+
+MCCXX    =
+MCLIBS   =
+
+CXXFLAGS += $(ROOTCXX) $(MCCXX) $(LOCALCXX)
+
+# define module specific variables
+FILE_LIST =  $(shell ls -1 ./*.$(SrcSuf))
+FILES = $(basename $(FILE_LIST))
+DICTIONARIES = kdTreeDict
+OBJECTS = $(addsuffix .$(ObjSuf),$(FILES))
+OBJECTS += ./$(DICTIONARIES).$(ObjSuf)
+
+#define headers
+HDRS = $(addsuffix .$(HdrSuf),$(FILES)) 
+HEADERS = $(notdir $(HDRS))
+
+# define libs on which the main lib depends ! (this are defined in config/Makefile.flags)
+LIBSDEPEND = $(ROOTLIBS) $(MCLIBS)
+# define libs build by module
+LIBS = libKDTree.so
+
+# rule for building executables
+$(EXECS):      $(OBJECTS)
+       @echo -e "\E[31mBuild executable: \E[1;31m$@\E[0m"
+       @$(LD) $(LIBSDEPEND) $^ -o $@
+       
+# rule for building libraries
+%.$(DllSuf):   $(OBJECTS)
+       @echo -e "\E[31mBuild library: \E[1;31m$@\E[0m"
+       @$(LD) $(SOFLAGS) $(LIBSDEPEND) $^ -o $@
+       
+# rule for building objects
+%.$(ObjSuf):   %.$(SrcSuf)
+       @echo -e "\E[31mCompile : \E[1;31m$^\E[0m"
+       @$(CXX) $(CXXFLAGS) -c $< -o $@
+
+#rule for building dictionary
+%Dict.$(SrcSuf): %LinkDef.h
+       @echo -e "\E[31mGenerate dictionary : \E[1;31m$@\E[0m"
+       @rootcint -f $@ -c $(CXXFLAGS) $(HEADERS) $^
+       
+all: $(OBJECTS) $(LIBS) $(EXECS)
+
+headers:
+       @if [ "$(HEADERS)" != "" ]; then \
+               if [ ! -d include ]; then mkdir include; fi; \
+               cp -f $(HEADERS) include; \
+       fi
+       
+clean:
+       @rm -fv $(DICTIONARIES)
+       @rm -fv $(OBJECTS)
+       @find . -name "*~" -a -exec rm -fv \{} \;
+       @if [ "$(LIBS)" != "" ]; then rm -fv ./$(LIBS); fi
+       @if [ "$(EXECS)" != "" ]; then rm -fv ./$(EXECS); fi
+
+       
+
+
diff --git a/STAT/TKDInterpolator.cxx b/STAT/TKDInterpolator.cxx
new file mode 100644 (file)
index 0000000..88bce8a
--- /dev/null
@@ -0,0 +1,298 @@
+#include "TKDInterpolator.h"
+
+#include "TLinearFitter.h"
+#include "TVector.h"
+#include "TTree.h"
+#include "TH2.h"
+#include "TObjArray.h"
+#include "TObjString.h"
+#include "TBox.h"
+#include "TGraph.h"
+#include "TMarker.h"
+
+
+
+ClassImp(TKDInterpolator)
+
+/////////////////////////////////////////////////////////////////////
+// Memory setup of protected data memebers
+// fRefPoints : evaluation point of PDF for each terminal node of underlying KD Tree.
+// | 1st terminal node (fNDim point coordinates) | 2nd terminal node (fNDim point coordinates) | ...
+//
+// fRefValues : evaluation value/error of PDF for each terminal node of underlying KD Tree.
+// | 1st terminal node (value) | 2nd terminal node (value) | ... | 1st terminal node (error) | 2nd terminal node (error) | ...
+/////////////////////////////////////////////////////////////////////
+
+//_________________________________________________________________
+TKDInterpolator::TKDInterpolator() : TKDTreeIF()
+       ,fNTNodes(0)
+       ,fRefPoints(0x0)
+       ,fRefValues(0x0)
+       ,fDepth(-1)
+       ,fTmpPoint(0x0)
+       ,fKDhelper(0x0)
+       ,fFitter(0x0)
+{
+}
+
+//_________________________________________________________________
+TKDInterpolator::TKDInterpolator(Int_t npoints, Int_t ndim, UInt_t bsize, Float_t **data) : TKDTreeIF(npoints, ndim, bsize, data)
+       ,fNTNodes(GetNTerminalNodes())
+       ,fRefPoints(0x0)
+       ,fRefValues(0x0)
+       ,fDepth(-1)
+       ,fTmpPoint(0x0)
+       ,fKDhelper(0x0)
+       ,fFitter(0x0)
+{
+       Build();
+}
+
+
+//_________________________________________________________________
+TKDInterpolator::TKDInterpolator(TTree *t, const Char_t *var, const Char_t *cut, UInt_t bsize) : TKDTreeIF()
+       ,fNTNodes(0)
+       ,fRefPoints(0x0)
+       ,fRefValues(0x0)
+       ,fDepth(-1)
+       ,fTmpPoint(0x0)
+       ,fKDhelper(0x0)
+       ,fFitter(0x0)
+{
+// Alocate data from a tree. The variables which have to be analysed are
+// defined in the "var" parameter as a colon separated list. The format should
+// be identical to that used by TTree::Draw().
+//
+// 
+
+       fNpoints = t->GetEntriesFast();
+       TObjArray *vars = TString(var).Tokenize(":");
+       fNDim = vars->GetEntriesFast();
+       if(fNDim > 6/*kDimMax*/) Warning("TKDInterpolator(TTree*, UInt_t, const Char_t)", Form("Variable number exceed maximum dimension %d. Results are unpredictable.", 6/*kDimMax*/));
+       fBucketSize = bsize;
+
+       printf("Allocating %d points in %d dimensions.\n", fNpoints, fNDim);
+       Float_t *mem = new Float_t[fNDim*fNpoints];
+       fData = new Float_t*[fNDim];
+       for(int idim=0; idim<fNDim; idim++) fData[idim] = &mem[idim*fNpoints];
+       kDataOwner = kTRUE;
+       
+       Double_t *v;
+       for(int idim=0; idim<fNDim; idim++){
+               if(!(t->Draw(((TObjString*)(*vars)[idim])->GetName(), cut, "goff"))){
+                       Warning("TKDInterpolator(TTree*, UInt_t, const Char_t)", Form("Can not access data for %s", ((TObjString*)(*vars)[idim])->GetName() ));
+                       continue;
+               }
+               v = t->GetV1();
+               for(int ip=0; ip<fNpoints; ip++) fData[idim][ip] = (Float_t)v[ip];
+       }
+       TKDTreeIF::Build();
+       fNTNodes = GetNTerminalNodes();
+       Build();
+}
+
+//_________________________________________________________________
+TKDInterpolator::~TKDInterpolator()
+{
+       if(fFitter) delete fFitter;
+       if(fKDhelper) delete fKDhelper;
+       if(fTmpPoint) delete [] fTmpPoint;
+       
+       if(fRefPoints){
+               for(int idim=0; idim<fNDim; idim++) delete [] fRefPoints[idim] ;
+               delete [] fRefPoints;
+       }
+       if(fRefValues) delete [] fRefValues;
+}
+
+//_________________________________________________________________
+void TKDInterpolator::Build()
+{
+       if(!fBoundaries) MakeBoundaries();
+       
+       // allocate memory for data
+       fRefValues = new Float_t[fNTNodes];
+       fRefPoints = new Float_t*[fNDim];
+       for(int id=0; id<fNDim; id++){
+               fRefPoints[id] = new Float_t[fNTNodes];
+               for(int in=0; in<fNTNodes; in++) fRefPoints[id][in] = 0.;
+       }
+
+       Float_t *bounds = 0x0;
+       Int_t *indexPoints;
+       for(int inode=0, tnode = fNnodes; inode<fNTNodes-1; inode++, tnode++){
+               fRefValues[inode] =  Float_t(fBucketSize)/fNpoints;
+               bounds = GetBoundary(tnode);
+               for(int idim=0; idim<fNDim; idim++) fRefValues[inode] /= (bounds[2*idim+1] - bounds[2*idim]);
+
+               indexPoints = GetPointsIndexes(tnode);
+               // loop points in this terminal node
+               for(int idim=0; idim<fNDim; idim++){
+                       for(int ip = 0; ip<fBucketSize; ip++) fRefPoints[idim][inode] += fData[idim][indexPoints[ip]];
+                       fRefPoints[idim][inode] /= fBucketSize;
+               }
+       }
+
+       // analyze last (incomplete) terminal node
+       Int_t counts = fNpoints%fBucketSize;
+       counts = counts ? counts : fBucketSize;
+       Int_t inode = fNTNodes - 1, tnode = inode + fNnodes;
+       fRefValues[inode] =  Float_t(counts)/fNpoints;
+       bounds = GetBoundary(tnode);
+       for(int idim=0; idim<fNDim; idim++) fRefValues[inode] /= (bounds[2*idim+1] - bounds[2*idim]);
+
+       indexPoints = GetPointsIndexes(tnode);
+       // loop points in this terminal node
+       for(int idim=0; idim<fNDim; idim++){
+               for(int ip = 0; ip<counts; ip++) fRefPoints[idim][inode] += fData[idim][indexPoints[ip]];
+               fRefPoints[idim][inode] /= counts;
+       }
+}
+
+//_________________________________________________________________
+Double_t TKDInterpolator::Eval(Float_t *point)
+{
+
+       // calculate number of parameters in the parabolic expresion
+       Int_t kNN = 1 + fNDim + fNDim*(fNDim+1)/2;
+
+       // prepare workers
+       if(!fTmpPoint) fTmpPoint = new Double_t[fNDim];
+       if(!fKDhelper) fKDhelper = new TKDTreeIF(GetNTerminalNodes(), fNDim, kNN, fRefPoints);
+       if(!fFitter){
+               // generate formula for nD
+               TString formula("1");
+               for(int idim=0; idim<fNDim; idim++){
+                       formula += Form("++x[%d]", idim);
+                       for(int jdim=idim; jdim<fNDim; jdim++) formula += Form("++x[%d]*x[%d]", idim, jdim);
+               }
+               fFitter = new TLinearFitter(kNN, formula.Data());
+       }
+       
+       Int_t kNN_old = 0;
+       Int_t *index;
+       Float_t dist;
+       fFitter->ClearPoints();
+       do{
+               if(!fKDhelper->FindNearestNeighbors(point, kNN, index, dist)){
+                       Error("Eval()", Form("Failed retriving %d neighbours for point:", kNN));
+                       for(int idim=0; idim<fNDim; idim++) printf("%f ", point[idim]);
+                       printf("\n");
+                       return -1;
+               }
+               for(int in=kNN_old; in<kNN; in++){
+                       for(int idim=0; idim<fNDim; idim++) fTmpPoint[idim] = fRefPoints[idim][index[in]];
+                       fFitter->AddPoint(fTmpPoint, TMath::Log(fRefValues[index[in]]), 1.);
+               }
+               kNN_old = kNN;
+               kNN += 4;
+       } while(fFitter->Eval());
+
+       // calculate evaluation
+       TVectorD par(kNN);
+       fFitter->GetParameters(par);
+       Double_t result = par[0];
+       Int_t ipar = 0;
+       for(int idim=0; idim<fNDim; idim++){
+               result += par[++ipar]*point[idim];
+               for(int jdim=idim; jdim<fNDim; jdim++) result += par[++ipar]*point[idim]*point[jdim];
+       }
+       return TMath::Exp(result);
+}
+
+
+//_________________________________________________________________
+void TKDInterpolator::DrawNodes(Int_t depth, Int_t ax1, Int_t ax2)
+{
+// Draw nodes structure projected on plane "ax1:ax2". The parameter
+// "depth" specifies the bucket size per node. If depth == -1 draw only
+// terminal nodes and evaluation points (default -1 i.e. bucket size per node equal bucket size specified by the user)
+
+       if(!fBoundaries) MakeBoundaries();
+
+       // Count nodes in specific view
+       Int_t nnodes = 0;
+       for(int inode = 0; inode <= 2*fNnodes; inode++){
+               if(depth == -1){
+                       if(!IsTerminal(inode)) continue;
+               } else if((inode+1) >> depth != 1) continue;
+               nnodes++;
+       }
+
+       //printf("depth %d nodes %d\n", depth, nnodes);
+       
+       //TH2 *h2 = new TH2S("hframe", "", 100, fRange[2*ax1], fRange[2*ax1+1], 100, fRange[2*ax2], fRange[2*ax2+1]);
+       TH2 *h2 = new TH2S("hframe", "", 100, 0., 1., 100, 0., 1.);
+       h2->Draw();
+       
+       const Float_t border = 0.;//1.E-4;
+       TBox **node_array = new TBox*[nnodes], *node;
+       Float_t *bounds = 0x0;
+       nnodes = 0;
+       for(int inode = 0; inode <= 2*fNnodes; inode++){
+               if(depth == -1){
+                       if(!IsTerminal(inode)) continue;
+               } else if((inode+1) >> depth != 1) continue;
+
+               node = node_array[nnodes++];
+               bounds = GetBoundary(inode);
+               node = new TBox(bounds[2*ax1]+border, bounds[2*ax2]+border, bounds[2*ax1+1]-border, bounds[2*ax2+1]-border);
+               node->SetFillStyle(0);  
+               node->SetFillColor(51+inode);
+               node->Draw();
+       }
+       if(depth != -1) return;
+
+       // Draw reference points
+       TGraph *ref = new TGraph(GetNTerminalNodes());
+       ref->SetMarkerStyle(2);
+       ref->SetMarkerColor(2);
+       Float_t val, error;
+       for(int inode = 0; inode < GetNTerminalNodes(); inode++) ref->SetPoint(inode, fRefPoints[ax1][inode], fRefPoints[ax2][inode]);
+       ref->Draw("p");
+       return;
+}
+
+//_________________________________________________________________
+void TKDInterpolator::DrawNode(Int_t tnode, Int_t ax1, Int_t ax2)
+{
+// Draw node "node" and the data points within.
+
+       if(tnode < 0 || tnode >= GetNTerminalNodes()){
+               Warning("DrawNode()", Form("Terminal node %d outside defined range.", tnode));
+               return;
+       }
+
+       //TH2 *h2 = new TH2S("hframe", "", 1, fRange[2*ax1], fRange[2*ax1+1], 1, fRange[2*ax2], fRange[2*ax2+1]);
+       TH2 *h2 = new TH2S("hframe", "", 1, 0., 1., 1, 0., 1.);
+       h2->Draw();
+
+       Int_t inode = tnode;
+       tnode += fNnodes;
+       // select zone of interest in the indexes array
+       Int_t *index = GetPointsIndexes(tnode);
+       Int_t nPoints = (tnode == 2*fNnodes) ? fNpoints%fBucketSize : fBucketSize;
+
+       printf("true index %d points %d\n", tnode, nPoints);
+
+       // draw data points
+       TGraph *g = new TGraph(nPoints);
+       g->SetMarkerStyle(3);
+       g->SetMarkerSize(.8);
+       for(int ip = 0; ip<nPoints; ip++) g->SetPoint(ip, fData[ax1][index[ip]], fData[ax2][index[ip]]);
+       g->Draw("p");
+
+       // draw estimation point
+       TMarker *m=new TMarker(fRefPoints[ax1][inode], fRefPoints[ax2][inode], 2);
+       m->SetMarkerColor(2);
+       m->Draw();
+       
+       // draw node contour
+       Float_t *bounds = GetBoundary(tnode);
+       TBox *n = new TBox(bounds[2*ax1], bounds[2*ax2], bounds[2*ax1+1], bounds[2*ax2+1]);
+       n->SetFillStyle(0);
+       n->Draw();
+       
+       return;
+}
+
diff --git a/STAT/TKDInterpolator.h b/STAT/TKDInterpolator.h
new file mode 100644 (file)
index 0000000..24212d2
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef ROOT_TKDInterpolator
+#define ROOT_TKDInterpolator
+
+#ifndef ROOT_TKDTree
+#include "TKDTree.h"
+#endif
+
+class TTree;
+class TLinearFitter;
+class TKDInterpolator : public TKDTreeIF
+{
+public:
+       TKDInterpolator();
+       TKDInterpolator(TTree *t, const Char_t *var, const Char_t *cut = 0, UInt_t bsize = 100);
+       TKDInterpolator(Int_t npoints, Int_t ndim, UInt_t bsize, Float_t **data);
+       ~TKDInterpolator();
+       
+       inline Bool_t   GetEstimate(Int_t node, Float_t *coord, Float_t &val, Float_t &error) const ;
+       Double_t Eval(Float_t *point);
+       void            DrawNodes(Int_t depth = -1, Int_t ax1 = 0, Int_t ax2 = 1);
+       void            DrawNode(Int_t node, Int_t ax1 = 0, Int_t ax2 = 1);
+private:
+       void            Build();
+       
+protected:
+       Int_t     fNTNodes;        //Number of evaluation data points
+       Float_t   **fRefPoints;    //[fNDim][fNTNodes]
+       Float_t   *fRefValues;     //[fNTNodes]
+
+private:
+       Int_t                   fDepth;        //! depth of the KD Tree structure used
+       Double_t        *fTmpPoint;    //! temporary storage for one data point
+       TKDTreeIF *fKDhelper;    //! kNN finder
+       TLinearFitter *fFitter;  //! linear fitter      
+
+       ClassDef(TKDInterpolator, 1)   // data interpolator based on KD tree
+};
+
+//__________________________________________________________________
+Bool_t TKDInterpolator::GetEstimate(Int_t node, Float_t *coord, Float_t &val, Float_t &error) const
+{
+       if(node < 0 || node > GetNTerminalNodes()) return kFALSE;
+
+       for(int idim=0; idim<fNDim; idim++) coord[idim] = fRefPoints[idim][node];
+       val   = fRefValues[node];
+       //error = ...;
+       return kTRUE;
+}
+
+#endif
+
diff --git a/STAT/TKDSpline.cxx b/STAT/TKDSpline.cxx
new file mode 100644 (file)
index 0000000..7f00d27
--- /dev/null
@@ -0,0 +1,39 @@
+#include "TKDSpline.h"
+
+
+
+ClassImp(TKDSpline)
+
+/////////////////////////////////////////////////////////////////////
+// Memory setup of protected data memebers
+// fRefPoints : evaluation point of PDF for each terminal node of underlying KD Tree.
+// | 1st terminal node (fNDim point coordinates) | 2nd terminal node (fNDim point coordinates) | ...
+//
+// fRefValues : evaluation value/error of PDF for each terminal node of underlying KD Tree.
+// | 1st terminal node (value) | 2nd terminal node (value) | ... | 1st terminal node (error) | 2nd terminal node (error) | ...
+/////////////////////////////////////////////////////////////////////
+
+//_________________________________________________________________
+TKDSpline::TKDSpline() : TKDInterpolator()
+{
+}
+
+//_________________________________________________________________
+TKDSpline::TKDSpline(Int_t npoints, Int_t ndim, UInt_t bsize, Float_t **data) : TKDInterpolator(npoints, ndim, bsize, data)
+{
+       Build();
+}
+
+
+//_________________________________________________________________
+TKDSpline::TKDSpline(TTree *t, const Char_t *var, const Char_t *cut, UInt_t bsize) : TKDInterpolator(t, var, cut, bsize)
+{
+       Build();
+}
+
+
+//_________________________________________________________________
+void TKDSpline::Build()
+{
+}
+
diff --git a/STAT/TKDSpline.h b/STAT/TKDSpline.h
new file mode 100644 (file)
index 0000000..c8c4ab8
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef ROOT_TKDSpline
+#define ROOT_TKDSpline
+
+#ifndef ROOT_TKDInterpolator
+#include "TKDInterpolator.h"
+#endif
+
+class TKDSpline : public TKDInterpolator
+{
+public:
+       TKDSpline();
+       TKDSpline(TTree *t, const Char_t *var, const Char_t *cut = 0, UInt_t bsize=100);
+       TKDSpline(Int_t npoints, Int_t ndim, UInt_t bsize, Float_t **data);
+
+private:
+       void            Build();
+       
+protected:
+
+private:
+
+       ClassDef(TKDSpline, 1)   // spline fitter based on KD tree
+};
+
+
+#endif
+
diff --git a/STAT/TKDTree.cxx b/STAT/TKDTree.cxx
new file mode 100644 (file)
index 0000000..e653312
--- /dev/null
@@ -0,0 +1,769 @@
+#include "TKDTree.h"
+
+#include "TString.h"
+#include <string.h>
+
+#ifndef R__ALPHA
+templateClassImp(TKDTree)
+#endif
+//////////////////////////////////////////////////////////////////////
+// Memory setup of protected data members:
+// 
+//     kDataOwner;  // Toggle ownership of the data
+//     fNnodes:
+//  size of branch node array, and index of first terminal node
+//     fNDim;       // number of variables
+//     fNpoints;    // number of multidimensional points
+//     fBucketSize; // number of data points per terminal node
+// 
+//     fIndPoints : array containing rearanged indexes according to nodes:
+//     | point indexes from 1st terminal node (fBucketSize elements) | ... | point indexes from the last terminal node (<= fBucketSize elements)
+// 
+//     Value   **fData;
+//     fRange : array containing the boundaries of the domain:
+//     | 1st dimension (min + max) | 2nd dimension (min + max) | ...
+//     fBoundaries : nodes boundaries
+//     | 1st node {1st dim * 2 elements | 2nd dim * 2 elements | ...} | 2nd node {...} | ...
+//     the nodes are arranged in the following order :
+//      - first fNnodes are primary nodes
+//      - after are the terminal nodes
+//     fNodes : array of primary nodes
+///////////////////////////////////////////////////////////////////////
+//_________________________________________________________________
+template <typename  Index, typename Value>
+TKDTree<Index, Value>::TKDTree() :
+       TObject()
+       ,kDataOwner(kFALSE)
+       ,fNnodes(0)
+       ,fNDim(0)
+       ,fNpoints(0)
+       ,fBucketSize(0)
+       ,fIndPoints(0x0)
+       ,fData(0x0)
+       ,fRange(0x0)
+       ,fBoundaries(0x0)
+       ,fNodes(0x0)
+       ,fkNN(0x0)
+{
+// Default constructor. Nothing is built
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+TKDTree<Index, Value>::TKDTree(Index npoints, Index ndim, UInt_t bsize, Value **data) :
+       TObject()
+       ,kDataOwner(kFALSE)
+       ,fNnodes(0)
+       ,fNDim(ndim)
+       ,fNpoints(npoints)
+       ,fBucketSize(bsize)
+       ,fIndPoints(0x0)
+       ,fData(data) //Columnwise!!!!!
+       ,fRange(0x0)
+       ,fBoundaries(0x0)
+       ,fNodes(0x0)
+       ,fkNN(0x0)
+{
+       // Allocate data by hand. See TKDTree(TTree*, const Char_t*) for an automatic method.
+       
+       Build();
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+TKDTree<Index, Value>::~TKDTree()
+{
+       if (fkNN) delete [] fkNN;
+       if (fNodes) delete [] fNodes;
+       if (fIndPoints) delete [] fIndPoints;
+       if (fRange) delete [] fRange;
+       if (fBoundaries) delete [] fBoundaries;
+       if (kDataOwner && fData){
+               for(int idim=0; idim<fNDim; idim++) delete [] fData[idim];
+               delete [] fData;
+       }
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+void TKDTree<Index, Value>::Build(){
+       //
+       // Build binning
+       //
+       // 1. calculate number of nodes
+       // 2. calculate first terminal row
+       // 3. initialize index array
+       // 4. non recursive building of the binary tree
+       //
+       //1.
+       fNnodes = fNpoints/fBucketSize-1;
+       if (fNpoints%fBucketSize) fNnodes++;
+       
+       //2.
+       fRowT0=0;
+       for (;(fNnodes+1)>(1<<fRowT0);fRowT0++);
+       fRowT0-=1;
+       //         2 = 2**0 + 1
+       //         3 = 2**1 + 1
+       //         4 = 2**1 + 2
+       //         5 = 2**2 + 1
+       //         6 = 2**2 + 2
+       //         7 = 2**2 + 3
+       //         8 = 2**2 + 4
+       
+       //3.
+       // allocate space for boundaries
+       fRange = new Value[2*fNDim];
+       fIndPoints= new Index[fNpoints];
+       for (Index i=0; i<fNpoints; i++) fIndPoints[i] = i;
+       fNodes  = new TKDNode[fNnodes];
+       //
+       fCrossNode = (1<<(fRowT0+1))-1;
+       if (fCrossNode<fNnodes) fCrossNode = 2*fCrossNode+1;
+       //
+       //  fOffset = (((fNnodes+1)-(1<<fRowT0)))*2;
+       Int_t   over   = (fNnodes+1)-(1<<fRowT0);
+       Int_t   filled = ((1<<fRowT0)-over)*fBucketSize;
+       fOffset = fNpoints-filled;
+       //
+//     printf("Row0      %d\n", fRowT0);
+//     printf("CrossNode %d\n", fCrossNode);
+//     printf("Offset    %d\n", fOffset);
+       //
+       //
+       //4.
+       //    stack for non recursive build - size 128 bytes enough
+       Int_t rowStack[128];
+       Int_t nodeStack[128];
+       Int_t npointStack[128];
+       Int_t posStack[128];
+       Int_t currentIndex = 0;
+       Int_t iter =0;
+       rowStack[0]    = 0;
+       nodeStack[0]   = 0;
+       npointStack[0] = fNpoints;
+       posStack[0]   = 0;
+       //
+       Int_t nbucketsall =0;
+       while (currentIndex>=0){
+               iter++;
+               //
+               Int_t npoints  = npointStack[currentIndex];
+               if (npoints<=fBucketSize) {
+                       //printf("terminal node : index %d iter %d\n", currentIndex, iter);
+                       currentIndex--;
+                       nbucketsall++;
+                       continue; // terminal node
+               }
+               Int_t crow     = rowStack[currentIndex];
+               Int_t cpos     = posStack[currentIndex];
+               Int_t cnode    = nodeStack[currentIndex];               
+               TKDNode * node = &(fNodes[cnode]);
+               //printf("currentIndex %d npoints %d node %d\n", currentIndex, npoints, cnode);
+               //
+               // divide points
+               Int_t nbuckets0 = npoints/fBucketSize;           //current number of  buckets
+               if (npoints%fBucketSize) nbuckets0++;            //
+               Int_t restRows = fRowT0-rowStack[currentIndex];  // rest of fully occupied node row
+               if (restRows<0) restRows =0;
+               for (;nbuckets0>(2<<restRows); restRows++);
+               Int_t nfull = 1<<restRows;
+               Int_t nrest = nbuckets0-nfull;
+               Int_t nleft =0, nright =0;
+               //
+               if (nrest>(nfull/2)){
+                       nleft  = nfull*fBucketSize;
+                       nright = npoints-nleft;
+               }else{
+                       nright = nfull*fBucketSize/2;
+                       nleft  = npoints-nright;
+               }
+       
+               //
+               //find the axis with biggest spread
+               Value maxspread=0;
+               Value tempspread, min, max;
+               Index axspread=0;
+               Value *array;
+               for (Int_t idim=0; idim<fNDim; idim++){
+                       array = fData[idim];
+                       Spread(npoints, array, fIndPoints+cpos, min, max);
+                       tempspread = max - min;
+                       if (maxspread < tempspread) {
+                               maxspread=tempspread;
+                               axspread = idim;
+                       }
+                       if(cnode==0) {fRange[2*idim] = min; fRange[2*idim+1] = max;}
+               }
+               array = fData[axspread];
+               KOrdStat(npoints, array, nleft, fIndPoints+cpos);
+               node->fAxis  = axspread;
+               node->fValue = array[fIndPoints[cpos+nleft]];
+               //printf("Set node %d : ax %d val %f\n", cnode, node->fAxis, node->fValue);
+               //
+               //
+               npointStack[currentIndex] = nleft;
+               rowStack[currentIndex]    = crow+1;
+               posStack[currentIndex]    = cpos;
+               nodeStack[currentIndex]   = cnode*2+1;
+               currentIndex++;
+               npointStack[currentIndex] = nright;
+               rowStack[currentIndex]    = crow+1;
+               posStack[currentIndex]    = cpos+nleft;
+               nodeStack[currentIndex]   = (cnode*2)+2;
+               //
+               if (0){
+                       // consistency check
+                       Info("Build()", Form("points %d left %d right %d", npoints, nleft, nright));
+                       if (nleft<nright) Warning("Build", "Problem Left-Right");
+                       if (nleft<0 || nright<0) Warning("Build()", "Problem Negative number");
+               }
+       }
+       OrderIndexes();
+       
+       //printf("NBuckets\t%d\n", nbucketsall);
+       //fData = 0;
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+Bool_t TKDTree<Index, Value>::FindNearestNeighbors(const Value *point, const Int_t k, Index *&in, Value &d)
+{
+// Find "k" nearest neighbors to "point".
+//
+// Return true in case of success and false in case of failure.
+// The indexes of the nearest k points are stored in the array "in" in
+// increasing order of the distance to "point" and the maxim distance
+// in "d".
+//
+// The array "in" is managed internally by the TKDTree.
+
+       Index inode = FindNode(point);
+       if(inode < fNnodes){
+               Error("FindNearestNeighbors()", "Point outside data range.");
+               return kFALSE;
+       }
+
+       // allocate working memory
+       if(!fkNN) fkNN = new Index[k];
+       if(sizeof(fkNN) < k*sizeof(Index)) fkNN = new(fkNN) Index[k];
+       for(int i=0; i<k; i++) fkNN[i] = -1;    
+       Index *fkNN_tmp = new Index[k];
+       Value *fkNN_dist = new Value[k];
+       for(int i=0; i<k; i++) fkNN_dist[i] = 9999.;
+       Value *fkNN_dist_tmp = new Value[k];
+       Value *dist = new Value[fBucketSize];
+       Index *index = new Index[fBucketSize];
+
+       // calculate number of boundaries with the data domain. 
+       Index nBounds = 0;
+       if(!fBoundaries) MakeBoundaries();
+       Value *bounds = &fBoundaries[inode*2*fNDim];
+       for(int idim=0; idim<fNDim; idim++){
+               if(bounds[2*idim] == fRange[2*idim]) nBounds++;
+               if(bounds[2*idim+1] == fRange[2*idim+1]) nBounds++;
+       }
+       
+       // traverse tree
+       TKDNode *node;
+       Int_t nodeStack[128], nodeIn[128];
+       Index currentIndex = 0;
+       nodeStack[0]   = inode;
+       nodeIn[0] = inode;
+       while(currentIndex>=0){
+               Int_t tnode = nodeStack[currentIndex];
+               Int_t entry = nodeIn[currentIndex];
+               currentIndex--;
+
+               // check if node is still eligible
+               node = &fNodes[tnode/2 + (tnode%2) - 1];
+               if((TMath::Abs(point[node->fAxis] - node->fValue) > fkNN_dist[k-1])
+                                                                                       &&
+                       ((point[node->fAxis] > node->fValue && tnode%2) ||
+                        (point[node->fAxis] < node->fValue && !tnode%2))) {
+                       //printf("\tREMOVE NODE\n");
+
+                       // mark bound
+                       nBounds++;
+                       // end all recursions
+                       if(nBounds==2 * fNDim) break;
+                       continue;
+               }
+               
+               if(IsTerminal(tnode)){
+                       // Link data to terminal node
+                       Int_t offset = (tnode >= fCrossNode) ? (tnode-fCrossNode)*fBucketSize : fOffset+(tnode-fNnodes)*fBucketSize;
+                       Index *indexPoints = &fIndPoints[offset];
+                       Int_t nPoints = (tnode == 2*fNnodes) ? fNpoints%fBucketSize : fBucketSize;
+                       for(int idx=0; idx<nPoints; idx++){
+                               // calculate distance in the L1 metric
+                               dist[idx] = 0.;
+                               for(int idim=0; idim<fNDim; idim++) dist[idx] += TMath::Abs(point[idim] - fData[idim][indexPoints[idx]]);
+                       }
+                       // arrange increasingly distances array and update kNN indexes
+                       TMath::Sort(nPoints, dist, index, kFALSE);
+                       for(int ibrowse=0; ibrowse<nPoints; ibrowse++){
+                               // exit if the current distance calculated in this node is
+                               // larger than the largest distance stored in the kNN array
+                               if(dist[index[ibrowse]] >= fkNN_dist[k-1]) break;
+                               for(int iNN=0; iNN<k; iNN++){
+                                       if(dist[index[ibrowse]] < fkNN_dist[iNN]){
+                                               //insert neighbor. In principle this is only one call to STL vector. Maybe we can change to it ?!
+                                               //printf("\t\tinsert data %d @ %d distance %f\n", indexPoints[index[ibrowse]], iNN, dist[index[ibrowse]]);
+                       
+                                               memcpy(fkNN_tmp, &fkNN[iNN], (k-iNN-1)*sizeof(Index));
+                                               fkNN[iNN] = indexPoints[index[ibrowse]];
+                                               memcpy(&fkNN[iNN+1], fkNN_tmp, (k-iNN-1)*sizeof(Index));
+
+                                               memcpy(fkNN_dist_tmp, &fkNN_dist[iNN], (k-iNN-1)*sizeof(Value));
+                                               fkNN_dist[iNN] = dist[index[ibrowse]];
+                                               memcpy(&fkNN_dist[iNN+1], fkNN_dist_tmp, (k-iNN-1)*sizeof(Value));
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               
+               // register parent
+               Int_t parent_node = tnode/2 + (tnode%2) - 1;
+               if(parent_node >= 0 && entry != parent_node){
+                       // check if parent node is eligible at all
+                       node = &fNodes[parent_node];
+                       if(TMath::Abs(point[node->fAxis] - node->fValue) > fkNN_dist[k-1]){
+                               // mark bound
+                               nBounds++;
+                               // end all recursions
+                               if(nBounds==2 * fNDim) break;
+                       }
+                       currentIndex++;
+                       nodeStack[currentIndex]=tnode/2 + (tnode%2) - 1;
+                       nodeIn[currentIndex]=tnode;
+                       //printf("\tregister %d\n", nodeStack[currentIndex]);
+               }
+
+               // register children nodes
+               Int_t child_node;
+               Bool_t kAllow[] = {kTRUE, kTRUE};
+               node = &fNodes[tnode];
+               if(TMath::Abs(point[node->fAxis] - node->fValue) > fkNN_dist[k-1]){
+                       if(point[node->fAxis] > node->fValue) kAllow[0] = kFALSE;
+                       else kAllow[1] = kFALSE;
+               }
+               for(int ic=1; ic<=2; ic++){
+                       if(!kAllow[ic-1]) continue;
+                       child_node = (tnode*2)+ic;
+                       if(child_node < fNnodes + GetNTerminalNodes() && entry != child_node){
+                               currentIndex++;
+                               nodeStack[currentIndex] = child_node;
+                               nodeIn[currentIndex]=tnode;
+                               //printf("\tregister %d\n", nodeStack[currentIndex]);
+                       }
+               }
+       }
+       // save results
+       in = fkNN;
+       d  = fkNN_dist[k-1];
+       
+       delete [] index;
+       delete [] dist;
+       delete [] fkNN_tmp;
+       delete [] fkNN_dist;
+       delete [] fkNN_dist_tmp;
+
+       return kTRUE;
+}
+
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+Index TKDTree<Index, Value>::FindNode(const Value * point){
+  //
+  // find the terminal node to which point belongs
+  
+       Index stackNode[128], inode;
+       Int_t currentIndex =0;
+       stackNode[0] = 0;
+       //
+       while (currentIndex>=0){
+               inode    = stackNode[currentIndex];
+               currentIndex--;
+               if (IsTerminal(inode)) return inode;
+               
+               TKDNode & node = fNodes[inode];
+               if (point[node.fAxis]<=node.fValue){
+                       currentIndex++;
+                       stackNode[currentIndex]=(inode*2)+1;
+               }
+               if (point[node.fAxis]>=node.fValue){
+                       currentIndex++;
+                       stackNode[currentIndex]=(inode*2)+2;
+               }
+       }
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+void TKDTree<Index, Value>::FindPoint(Value * point, Index &index, Int_t &iter){
+  //
+  // find the index of point
+  // works only if we keep fData pointers
+  
+       Int_t stackNode[128];
+       Int_t currentIndex =0;
+       stackNode[0] = 0;
+       iter =0;
+       //
+       while (currentIndex>=0){
+               iter++;
+               Int_t inode    = stackNode[currentIndex];
+               currentIndex--;
+               if (IsTerminal(inode)){
+                       // investigate terminal node
+                       Int_t indexIP  = (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNnodes)*fBucketSize+fOffset;
+                       printf("terminal %d indexP %d\n", inode, indexIP);
+                       for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
+                               Bool_t isOK    = kTRUE;
+                               indexIP+=ibucket;
+                               printf("ibucket %d index %d\n", ibucket, indexIP);
+                               if (indexIP>=fNpoints) continue;
+                               Int_t index0   = fIndPoints[indexIP];
+                               for (Int_t idim=0;idim<fNDim;idim++) if (fData[idim][index0]!=point[idim]) isOK = kFALSE;
+                               if (isOK) index = index0;
+                       }
+                       continue;
+               }
+               
+               TKDNode & node = fNodes[inode];
+               if (point[node.fAxis]<=node.fValue){
+                       currentIndex++;
+                       stackNode[currentIndex]=(inode*2)+1;
+               }
+               if (point[node.fAxis]>=node.fValue){
+                       currentIndex++;
+                       stackNode[currentIndex]=(inode*2)+2;
+               }
+       }
+  //
+  //  printf("Iter\t%d\n",iter);
+}
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+void TKDTree<Index, Value>::FindInRangeA(Value * point, Value * delta, Index *res , Index &npoints, Index & iter, Int_t bnode)
+{
+ //
+  // Find all points in the range specified by    (point +- range)
+  // res     - Resulting indexes are stored in res array 
+  // npoints - Number of selected indexes in range
+  // NOTICE:
+  // For some cases it is better to don't keep data - because of memory consumption
+  // If the data are not kept - only boundary conditions are investigated
+  // some of the data can be outside of the range
+  // What is guranteed in this mode: All of the points in the range are selected + some fraction of others (but close)
+
+       Index stackNode[128];
+  iter=0;
+  Index currentIndex = 0;
+  stackNode[currentIndex] = bnode; 
+  while (currentIndex>=0){
+    iter++;
+    Int_t inode    = stackNode[currentIndex];
+    //
+    currentIndex--;
+    if (!IsTerminal(inode)){
+      // not terminal
+      TKDNode * node = &(fNodes[inode]);
+      if (point[node->fAxis] - delta[node->fAxis] <  node->fValue) {
+       currentIndex++; 
+       stackNode[currentIndex]= (inode*2)+1;
+      }
+      if (point[node->fAxis] + delta[node->fAxis] >= node->fValue){
+       currentIndex++; 
+       stackNode[currentIndex]= (inode*2)+2;
+      }
+    }else{
+      Int_t indexIP  = 
+       (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNnodes)*fBucketSize+fOffset;
+      for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
+       if (indexIP+ibucket>=fNpoints) break;
+       res[npoints]   = fIndPoints[indexIP+ibucket];
+       npoints++;
+      }
+    }
+  }
+  if (fData){
+    //
+    //  compress rest if data still accesible
+    //
+    Index npoints2 = npoints;
+    npoints=0;
+    for (Index i=0; i<npoints2;i++){
+      Bool_t isOK = kTRUE;
+      for (Index idim = 0; idim< fNDim; idim++){
+       if (TMath::Abs(fData[idim][res[i]]- point[idim])>delta[idim]) 
+         isOK = kFALSE;        
+      }
+      if (isOK){
+       res[npoints] = res[i];
+       npoints++;
+      }
+    }    
+  }
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+void TKDTree<Index, Value>::FindInRangeB(Value * point, Value * delta, Index *res , Index &npoints,Index & iter, Int_t bnode)
+{
+  //
+  Long64_t  goldStatus = (1<<(2*fNDim))-1;  // gold status
+  Index stackNode[128];
+  Long64_t   stackStatus[128]; 
+  iter=0;
+  Index currentIndex   = 0;
+  stackNode[currentIndex]   = bnode; 
+  stackStatus[currentIndex] = 0;
+  while (currentIndex>=0){
+    Int_t inode     = stackNode[currentIndex];
+    Long64_t status = stackStatus[currentIndex];
+    currentIndex--;
+    iter++;
+    if (IsTerminal(inode)){
+      Int_t indexIP  = 
+       (inode >= fCrossNode) ? (inode-fCrossNode)*fBucketSize : (inode-fNnodes)*fBucketSize+fOffset;
+      for (Int_t ibucket=0;ibucket<fBucketSize;ibucket++){
+       if (indexIP+ibucket>=fNpoints) break;
+       res[npoints]   = fIndPoints[indexIP+ibucket];
+       npoints++;
+      }
+      continue;
+    }      
+    // not terminal    
+    if (status == goldStatus){
+      Int_t ileft  = inode;
+      Int_t iright = inode;
+      for (;ileft<fNnodes; ileft   = (ileft<<1)+1);
+      for (;iright<fNnodes; iright = (iright<<1)+2);
+      Int_t indexL  = 
+       (ileft >= fCrossNode) ? (ileft-fCrossNode)*fBucketSize : (ileft-fNnodes)*fBucketSize+fOffset;
+      Int_t indexR  = 
+       (iright >= fCrossNode) ? (iright-fCrossNode)*fBucketSize : (iright-fNnodes)*fBucketSize+fOffset;
+      if (indexL<=indexR){
+       Int_t endpoint = indexR+fBucketSize;
+       if (endpoint>fNpoints) endpoint=fNpoints;
+       for (Int_t ipoint=indexL;ipoint<endpoint;ipoint++){
+         res[npoints]   = fIndPoints[ipoint];
+         npoints++;
+       }         
+       continue;
+      }
+    }
+    //
+    TKDNode * node = &(fNodes[inode]);
+    if (point[node->fAxis] - delta[node->fAxis] <  node->fValue) {
+      currentIndex++; 
+      stackNode[currentIndex]= (inode<<1)+1;
+      if (point[node->fAxis] + delta[node->fAxis] > node->fValue) 
+       stackStatus[currentIndex]= status | (1<<(2*node->fAxis));
+    }
+    if (point[node->fAxis] + delta[node->fAxis] >= node->fValue){
+      currentIndex++; 
+      stackNode[currentIndex]= (inode<<1)+2;
+      if (point[node->fAxis] - delta[node->fAxis]<node->fValue) 
+       stackStatus[currentIndex]= status | (1<<(2*node->fAxis+1));
+    }
+  }
+  if (fData){
+    // compress rest
+    Index npoints2 = npoints;
+    npoints=0;
+    for (Index i=0; i<npoints2;i++){
+      Bool_t isOK = kTRUE;
+      for (Index idim = 0; idim< fNDim; idim++){
+       if (TMath::Abs(fData[idim][res[i]]- point[idim])>delta[idim]) 
+         isOK = kFALSE;        
+      }
+      if (isOK){
+       res[npoints] = res[i];
+       npoints++;
+      }
+    }    
+  }
+}
+
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+void TKDTree<Index, Value>::SetData(Index npoints, Index ndim, UInt_t bsize, Value **data)
+{
+// TO DO
+// 
+// Check reconstruction/reallocation of memory of data. Maybe it is not
+// necessary to delete and realocate space but only to use the same space
+
+       Clear();
+  
+       //Columnwise!!!!
+   fData = data;
+   fNpoints = npoints;
+   fNDim = ndim;
+   fBucketSize = bsize;
+
+       Build();
+}
+
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+void TKDTree<Index, Value>::Spread(Index ntotal, Value *a, Index *index, Value &min, Value &max)
+{
+  //Value min, max;
+  Index i;
+  min = a[index[0]];
+  max = a[index[0]];
+  for (i=0; i<ntotal; i++){
+    if (a[index[i]]<min) min = a[index[i]];
+    if (a[index[i]]>max) max = a[index[i]];
+  }
+}
+
+
+//_________________________________________________________________
+template <typename  Index, typename Value>
+Value TKDTree<Index, Value>::KOrdStat(Index ntotal, Value *a, Index k, Index *index)
+{
+  //
+   //copy of the TMath::KOrdStat because I need an Index work array
+
+   Index i, ir, j, l, mid;
+   Index arr;
+   Index temp;
+
+   Index rk = k;
+   l=0;
+   ir = ntotal-1;
+  for(;;) {
+      if (ir<=l+1) { //active partition contains 1 or 2 elements
+         if (ir == l+1 && a[index[ir]]<a[index[l]])
+           {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
+         Value tmp = a[index[rk]];
+         return tmp;
+      } else {
+         mid = (l+ir) >> 1; //choose median of left, center and right
+         {temp = index[mid]; index[mid]=index[l+1]; index[l+1]=temp;}//elements as partitioning element arr.
+         if (a[index[l]]>a[index[ir]])  //also rearrange so that a[l]<=a[l+1]
+           {temp = index[l]; index[l]=index[ir]; index[ir]=temp;}
+
+         if (a[index[l+1]]>a[index[ir]])
+           {temp=index[l+1]; index[l+1]=index[ir]; index[ir]=temp;}
+
+         if (a[index[l]]>a[index[l+1]])
+           {temp = index[l]; index[l]=index[l+1]; index[l+1]=temp;}
+
+         i=l+1;        //initialize pointers for partitioning
+         j=ir;
+         arr = index[l+1];
+         for (;;) {
+           do i++; while (a[index[i]]<a[arr]);
+           do j--; while (a[index[j]]>a[arr]);
+           if (j<i) break;  //pointers crossed, partitioning complete
+              {temp=index[i]; index[i]=index[j]; index[j]=temp;}
+         }
+         index[l+1]=index[j];
+         index[j]=arr;
+         if (j>=rk) ir = j-1; //keep active the partition that
+         if (j<=rk) l=i;      //contains the k_th element
+      }
+   }
+}
+
+//_________________________________________________________________
+template <typename Index, typename Value>
+void TKDTree<Index, Value>::MakeBoundaries(Value *range)
+{
+// Build boundaries for each node.
+
+
+       if(range) memcpy(fRange, range, 2*fNDim*sizeof(Value));
+       // total number of nodes including terminal nodes
+       Int_t totNodes = fNnodes + GetNTerminalNodes();
+       fBoundaries = new Value[totNodes*2*fNDim];
+       printf("Allocate %d nodes\n", totNodes);
+       // loop
+       Int_t child_index;
+       for(int inode=fNnodes-1; inode>=0; inode--){
+               //printf("\tAllocate node %d\n", inode);
+               memcpy(&fBoundaries[inode*2*fNDim], fRange, 2*fNDim*sizeof(Value));
+                               
+               // check left child node
+               child_index = 2*inode+1;
+               if(IsTerminal(child_index)) CookBoundariesTerminal(inode, kTRUE);
+               for(int idim=0; idim<fNDim; idim++) fBoundaries[2*fNDim*inode+2*idim] = fBoundaries[2*fNDim*child_index+2*idim];
+               
+               // check right child node
+               child_index = 2*inode+2;
+               if(IsTerminal(child_index)) CookBoundariesTerminal(inode, kFALSE);
+               for(int idim=0; idim<fNDim; idim++) fBoundaries[2*fNDim*inode+2*idim+1] = fBoundaries[2*fNDim*child_index+2*idim+1];
+       }
+}
+
+//_________________________________________________________________
+template <typename Index, typename Value>
+void TKDTree<Index, Value>::CookBoundariesTerminal(Int_t parent_node, Bool_t LEFT)
+{
+       // define index of this terminal node
+       Int_t index = 2 * parent_node + (LEFT ? 1 : 2);
+       
+       // build and initialize boundaries for this node
+       //printf("\tAllocate terminal node %d\n", index);
+       memcpy(&fBoundaries[2*fNDim*index], fRange, 2*fNDim*sizeof(Value));
+       Bool_t flag[256];  // cope with up to 128 dimensions 
+       memset(flag, kFALSE, 2*fNDim);
+       Int_t nvals = 0;
+               
+       // recurse parent nodes
+       TKDNode *node = 0x0;
+       while(parent_node >= 0 && nvals < 2 * fNDim){
+               node = &(fNodes[parent_node]);
+               if(LEFT){
+                       if(!flag[2*node->fAxis+1]) {
+                               fBoundaries[2*fNDim*index+2*node->fAxis+1] = node->fValue;
+                               flag[2*node->fAxis+1] = kTRUE;
+                               nvals++;
+                       }
+               } else {
+                       if(!flag[2*node->fAxis]) {
+                               fBoundaries[2*fNDim*index+2*node->fAxis] = node->fValue;
+                               flag[2*node->fAxis] = kTRUE;
+                               nvals++;
+                       }
+               }
+               LEFT = parent_node%2;
+               parent_node =  parent_node/2 + (parent_node%2) - 1;
+       }
+}
+
+//_________________________________________________________________
+template <typename Index, typename Value>
+void TKDTree<Index, Value>::OrderIndexes()
+{
+// Order array of point's indexes in increasing order of terminal nodes
+// indexes such that first bucket points correspond to first terminal
+// node (index fNnodes) and so on.
+
+       printf("fRowT0 %d fCrossNode %d fOffset %d\n", fRowT0, fCrossNode, fOffset);
+
+}
+
+template class TKDTree<Int_t, Float_t>;
+template class TKDTree<Int_t, Double_t>;
+
diff --git a/STAT/TKDTree.h b/STAT/TKDTree.h
new file mode 100644 (file)
index 0000000..fb476c8
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef ROOT_TKDTree
+#define ROOT_TKDTree
+
+#ifndef ROOT_TObject
+#include "TObject.h"
+#endif
+
+#include "TMath.h"
+template <typename Index, typename Value> class TKDTree : public TObject
+{
+public:
+       enum{
+               kDimMax = 6
+       };
+
+       TKDTree();
+       TKDTree(Index npoints, Index ndim, UInt_t bsize, Value **data);
+       ~TKDTree();
+       
+       // getters
+                                       inline  Index*  GetPointsIndexes(Int_t node) const {
+                                               if(node < fNnodes) return 0x0;
+                                               Int_t offset = (node >= fCrossNode) ? (node-fCrossNode)*fBucketSize : fOffset+(node-fNnodes)*fBucketSize;
+                                               return &fIndPoints[offset];
+                                       }
+                                       inline Char_t           GetNodeAxis(Int_t id) const {return (id < 0 || id >= fNnodes) ? 0 : fNodes[id].fAxis;}
+                                       inline Value            GetNodeValue(Int_t id) const {return (id < 0 || id >= fNnodes) ? 0 : fNodes[id].fValue;}
+                                       inline Int_t            GetNNodes() const {return fNnodes;}
+                                       inline Int_t            GetNTerminalNodes() const {return fNpoints/fBucketSize + ((fNpoints%fBucketSize)?1:0);}
+                                       inline Value*           GetBoundaries() const {return fBoundaries;}
+                                       inline Value*           GetBoundary(const Int_t node) const {return &fBoundaries[node*2*fNDim];}
+       static                                  Int_t           GetIndex(Int_t row, Int_t collumn){return collumn+(1<<row);}
+       static  inline  void            GetCoord(Int_t index, Int_t &row, Int_t &collumn){for (row=0; index>=(16<<row);row+=4); for (; index>=(2<<row);row++);collumn= index-(1<<row);};
+                                                                       Bool_t  FindNearestNeighbors(const Value *point, const Int_t kNN, Index *&i, Value &d);
+                                                                       Index           FindNode(const Value * point);
+                                                                       void            FindPoint(Value * point, Index &index, Int_t &iter);
+                                                                       void            FindInRangeA(Value * point, Value * delta, Index *res , Index &npoints,Index & iter, Int_t bnode);
+                                                                       void            FindInRangeB(Value * point, Value * delta, Index *res , Index &npoints,Index & iter, Int_t bnode);
+                                       inline  void            FindBNodeA(Value * point, Value * delta, Int_t &inode);
+       //
+                                       inline  Bool_t  IsTerminal(Index inode){return (inode>=fNnodes);}
+       //
+                                                                       Value           KOrdStat(Index ntotal, Value *a, Index k, Index *index);
+                                                                       void            MakeBoundaries(Value *range = 0x0);
+                                                                       
+                                                                       void            SetData(Index npoints, Index ndim, UInt_t bsize, Value **data);
+       //
+                                                                       void            Spread(Index ntotal, Value *a, Index *index, Value &min, Value &max);
+
+protected:
+                                                                       void            Build();  // build tree
+                                                                       void            Clear(){};  // clear memory allocation
+                                                                       
+private:
+                                                                       void            CookBoundariesTerminal(Int_t parent_node, Bool_t left);
+                                                                       void            OrderIndexes();
+public:
+       struct TKDNode{
+               Char_t fAxis;
+               Value  fValue;
+       };
+
+protected:
+       Bool_t  kDataOwner;  // Toggle ownership of the data
+       Int_t   fNnodes;     // size of node array
+       Index   fNDim;       // number of variables
+       Index   fNpoints;    // number of multidimensional points
+       Index   fBucketSize; // limit statistic for nodes 
+       Value   **fData;     //!
+       Value           *fRange;     //! range of data for each dimension     
+       Value           *fBoundaries;//! nodes boundaries - check class doc
+       TKDNode *fNodes;
+       Index   *fkNN;       //! k nearest neighbors
+
+private:
+       Index   *fIndPoints; //! array of points indexes
+       Int_t   fRowT0;      // smallest terminal row
+       Int_t   fCrossNode;  // cross node
+       Int_t   fOffset;     // offset in fIndPoints
+
+       ClassDef(TKDTree, 1)  // KD tree
+};
+
+
+typedef TKDTree<Int_t, Double_t> TKDTreeID;
+typedef TKDTree<Int_t, Float_t> TKDTreeIF;
+
+//_________________________________________________________________
+template <typename  Index, typename Value> void TKDTree<Index, Value>::FindBNodeA(Value *point, Value *delta, Int_t &inode){
+  //
+  // find the smallest node covering the full range - start
+  //
+  inode =0; 
+  for (;inode<fNnodes;){
+    TKDNode & node = fNodes[inode];
+    if (TMath::Abs(point[node.fAxis] - node.fValue)<delta[node.fAxis]) break;
+    inode = (point[node.fAxis] < node.fValue) ? (inode*2)+1: (inode*2)+2;    
+  }
+}
+
+#endif
+
diff --git a/STAT/kdTreeLinkDef.h b/STAT/kdTreeLinkDef.h
new file mode 100644 (file)
index 0000000..e852ab5
--- /dev/null
@@ -0,0 +1,17 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class TKDTree<Int_t, Float_t>+;
+#pragma link C++ class TKDTree <Int_t, Double_t>+;
+#pragma link C++ typedef TKDTreeIF;
+#pragma link C++ typedef TKDTreeID;
+
+#pragma link C++ class TKDInterpolator+;
+#pragma link C++ class TKDSpline+;
+
+
+#endif
+