Index: /trunk/Delphes.cpp
===================================================================
--- /trunk/Delphes.cpp	(revision 10)
+++ /trunk/Delphes.cpp	(revision 11)
@@ -19,9 +19,4 @@
 #include "Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h"
 
-#include "Utilities/CDFCones/interface/JetCluAlgorithm.h"
-#include "Utilities/CDFCones/interface/MidPointAlgorithm.h"
-#include "Utilities/CDFCones/interface/PhysicsTower.h"
-#include "Utilities/CDFCones/interface/Cluster.h"
-
 #include "H_BeamParticle.h"
 #include "H_BeamLine.h"
@@ -34,4 +29,23 @@
 
 #include "interface/SmearUtil.h"
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence.hh"
+
+// get info on how fastjet was configured
+#include "Utilities/Fastjet/include/fastjet/config.h"
+
+// make sure we have what is needed
+#ifdef ENABLE_PLUGIN_SISCONE
+#  include "Utilities/Fastjet/plugins/SISCone/SISConePlugin.hh"
+#endif
+#ifdef ENABLE_PLUGIN_CDFCONES
+#  include "Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.hh"
+#  include "Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.hh"
+#endif
+
+#include<vector>
+#include<iostream>
+
+
 
 using namespace std;
@@ -154,6 +168,9 @@
   vector<TLorentzVector> TrackCentral;  
   vector<PhysicsTower> towers;
-  vector<Cluster> jets; 
-
+
+  vector<fastjet::PseudoJet> input_particles;//for FastJet algorithm
+  vector<fastjet::PseudoJet> inclusive_jets;
+  vector<fastjet::PseudoJet> sorted_jets;
+  
   //Initialisation of Hector
   extern bool relative_energy;
@@ -161,7 +178,7 @@
   extern int kickers_on;
   kickers_on = 1;	  // should always be 1
-
-  	// user should provide : (1) optics file for each beamline, and IPname, 
-	  // and offset data (s,x) for optical elements
+  
+  // user should provide : (1) optics file for each beamline, and IPname, 
+  // and offset data (s,x) for optical elements
   H_BeamLine* beamline1 = new H_BeamLine(1,500.);
   beamline1->fill("data/LHCB1IR5_v6.500.tfs",1,"IP5");
@@ -171,5 +188,5 @@
   beamline1->add(rp220_1);
   beamline1->add(rp420_1);
-
+  
   H_BeamLine* beamline2 = new H_BeamLine(1,500.);
   beamline2->fill("data/LHCB1IR5_v6.500.tfs",-1,"IP5");
@@ -197,4 +214,5 @@
       TrackCentral.clear();
       towers.clear();
+      input_particles.clear();
       TSimpleArray<TRootGenParticle> NFCentralQ;
 
@@ -266,116 +284,119 @@
 		      break;
 		} // switch (pid)
-
+		
 		// all final particles but muons and neutrinos	
 		// for calorimetric towers and mission PT
 		if(genMomentum.E()!=0) {
-			PTmis = PTmis + genMomentum;//ptmis
-			if(pid !=pMU) {
-			      towers.push_back(PhysicsTower(LorentzVector(genMomentum.Px(),genMomentum.Py(),genMomentum.Pz(), genMomentum.E())));
-			      elementCalo = (TRootCalo*) branchCalo->NewEntry();
-			      elementCalo->Set(genMomentum);
-			}
+		  PTmis = PTmis + genMomentum;//ptmis
+		  if(pid !=pMU) {
+		    towers.push_back(PhysicsTower(LorentzVector(genMomentum.Px(),genMomentum.Py(),genMomentum.Pz(), genMomentum.E())));
+		    // create a fastjet::PseudoJet with these components and put it onto
+		    // back of the input_particles vector
+		    input_particles.push_back(fastjet::PseudoJet(genMomentum.Px(),genMomentum.Py(),genMomentum.Pz(), genMomentum.E())); 
+		    elementCalo = (TRootCalo*) branchCalo->NewEntry();
+		    elementCalo->Set(genMomentum);
+		  }
 		}
-
-
+		
+		
 		// all final charged particles
 		if(
-		     ((rand()%100) < DET->TRACKING_EFF)  &&
-		     (genMomentum.E()!=0) &&
-		     (fabs(particle->Eta) < DET->MAX_TRACKER) && 
-		     (genMomentum.Pt() > DET->PT_TRACKS_MIN ) &&     // pt too small to be taken into account
-		     (pid != pGAMMA)    && 
-		     (pid != pPI0)      &&
-		     (pid != pK0L)      &&
-		     (pid != pN)        &&
-		     (pid != pSIGMA0)   &&
-		     (pid != pDELTA0)   &&
-		     (pid != pK0S)   // not charged particles : invisible by tracker
-                 )
-		    {
-		      elementTracks = (TRootTracks*) branchTracks->NewEntry();
-		      elementTracks->Set(genMomentum);
-		      TrackCentral.push_back(genMomentum);
-		    }
-	    } // switch
-
+		   ((rand()%100) < DET->TRACKING_EFF)  &&
+		   (genMomentum.E()!=0) &&
+		   (fabs(particle->Eta) < DET->MAX_TRACKER) && 
+		   (genMomentum.Pt() > DET->PT_TRACKS_MIN ) &&     // pt too small to be taken into account
+		   (pid != pGAMMA)    && 
+		   (pid != pPI0)      &&
+		   (pid != pK0L)      &&
+		   (pid != pN)        &&
+		   (pid != pSIGMA0)   &&
+		   (pid != pDELTA0)   &&
+		   (pid != pK0S)   // not charged particles : invisible by tracker
+		   )
+		  {
+		    elementTracks = (TRootTracks*) branchTracks->NewEntry();
+		    elementTracks->Set(genMomentum);
+		    TrackCentral.push_back(genMomentum);
+		  }
+	  } // switch
+	  
 	  // Forward particles in CASTOR ?
-/*	  if (particle->Status == 1 && (fabs(particle->Eta) > DET->MIN_CALO_VFWD) 
-                                    && (fabs(particle->Eta) < DET->MAX_CALO_VFWD)) {
-		
-
-	  } // CASTOR
-*/
+	  /*	  if (particle->Status == 1 && (fabs(particle->Eta) > DET->MIN_CALO_VFWD) 
+		  && (fabs(particle->Eta) < DET->MAX_CALO_VFWD)) {
+		  
+		  
+		  } // CASTOR
+	  */
 	  // Zero degree calorimeter, for forward neutrons and photons
 	  if (particle->Status ==1 && (pid == pN || pid == pGAMMA ) && eta > DET->MIN_ZDC ) {
-// !!!!!!!!! vÃ©rifier que particle->Z est bien en micromÃštres!!!
-// !!!!!!!!! vÃ©rifier que particle->T est bien en secondes!!!
-// !!!!!!!!! pas de smearing ! on garde trop d'info !
-		elementZdc = (TRootZdcHits*) branchZDC->NewEntry();
-		elementZdc->Set(genMomentum);
-
-		// time of flight t is t = T + d/[ cos(theta) v ]
-		//double tx = acos(particle->Px/particle->Pz);
-		//double ty = acos(particle->Py/particle->Pz);
-		//double theta = (1E-6)*sqrt( pow(tx,2) + pow(ty,2) );
-		//double flight_distance = (DET->ZDC_S - particle->Z*(1E-6))/cos(theta) ; // assumes that Z is in micrometers
-		double flight_distance = (DET->ZDC_S - particle->Z*(1E-6)); 
-			// assumes also that the emission angle is so small that 1/(cos theta) = 1
-		elementZdc->T = 0*particle->T + flight_distance/speed_of_light; // assumes highly relativistic particles 
-		elementZdc->side = sign(particle->Eta);
-
+	    // !!!!!!!!! vÃ©rifier que particle->Z est bien en micromÃštres!!!
+	    // !!!!!!!!! vÃ©rifier que particle->T est bien en secondes!!!
+	    // !!!!!!!!! pas de smearing ! on garde trop d'info !
+	    elementZdc = (TRootZdcHits*) branchZDC->NewEntry();
+	    elementZdc->Set(genMomentum);
+	    
+	    // time of flight t is t = T + d/[ cos(theta) v ]
+	    //double tx = acos(particle->Px/particle->Pz);
+	    //double ty = acos(particle->Py/particle->Pz);
+	    //double theta = (1E-6)*sqrt( pow(tx,2) + pow(ty,2) );
+	    //double flight_distance = (DET->ZDC_S - particle->Z*(1E-6))/cos(theta) ; // assumes that Z is in micrometers
+	    double flight_distance = (DET->ZDC_S - particle->Z*(1E-6)); 
+	    // assumes also that the emission angle is so small that 1/(cos theta) = 1
+	    elementZdc->T = 0*particle->T + flight_distance/speed_of_light; // assumes highly relativistic particles 
+	    elementZdc->side = sign(particle->Eta);
+	    
 	  }
-
+	  
 	  // if forward proton
           if( (pid == pP)  && (particle->Status == 1) &&  (fabs(particle->Eta) > DET->MAX_CALO_FWD) ) 
             {
-// !!!!!!!! put here particle->CHARGE and particle->MASS
-		H_BeamParticle p1; /// put here particle->CHARGE and particle->MASS
-		p1.smearAng();
-                p1.smearPos();
-                p1.setPosition(p1.getX()-500.,p1.getY(),p1.getTX()-1*kickers_on*CRANG,p1.getTY(),0);
-		p1.set4Momentum(particle->Px,particle->Py,particle->Pz,particle->E);
-
-		H_BeamLine *beamline;
-		if(particle->Eta >0) beamline = beamline1;
-		else beamline = beamline2;
-
-		p1.computePath(beamline,1);
-
-		if(p1.stopped(beamline)) {
- 		    if (p1.getStoppingElement()->getName()=="rp220_1" || p1.getStoppingElement()->getName()=="rp220_2") {
-			p1.propagate(DET->RP220_S);
-			elementRP220 = (TRootRomanPotHits*) branchRP220->NewEntry();
-	                elementRP220->X  = (1E-6)*p1.getX();  // [m]
-        	        elementRP220->Y  = (1E-6)*p1.getY();  // [m]
-                	elementRP220->Tx = (1E-6)*p1.getTX(); // [rad]
-	                elementRP220->Ty = (1E-6)*p1.getTY(); // [rad]
-        	        elementRP220->S = p1.getS();          // [m]
-                	elementRP220->T = -1; 		// not yet implemented
-                        elementRP220->E = p1.getE(); 	// not yet implemented
-                        elementRP220->q2 = -1; 		// not yet implemented
-                	elementRP220->side = sign(particle->Eta); 
-
-		    } else if (p1.getStoppingElement()->getName()=="rp420_1" || p1.getStoppingElement()->getName()=="rp420_2") {
-			p1.propagate(DET->FP420_S);
-                        elementFP420 = (TRootRomanPotHits*) branchFP420->NewEntry();
-                        elementFP420->X  = (1E-6)*p1.getX();  // [m]
-                        elementFP420->Y  = (1E-6)*p1.getY();  // [m]
-                        elementFP420->Tx = (1E-6)*p1.getTX(); // [rad]
-                        elementFP420->Ty = (1E-6)*p1.getTY(); // [rad]
-                        elementFP420->S = p1.getS();	      // [m]
-                        elementFP420->T = -1; 		      // not yet implemented
-                        elementFP420->E = p1.getE();          // not yet implemented
-                        elementFP420->q2 = -1;                // not yet implemented
-                        elementFP420->side = sign(particle->Eta);
-                    }
+	      // !!!!!!!! put here particle->CHARGE and particle->MASS
+	      H_BeamParticle p1; /// put here particle->CHARGE and particle->MASS
+	      p1.smearAng();
+	      p1.smearPos();
+	      p1.setPosition(p1.getX()-500.,p1.getY(),p1.getTX()-1*kickers_on*CRANG,p1.getTY(),0);
+	      p1.set4Momentum(particle->Px,particle->Py,particle->Pz,particle->E);
+	      
+	      H_BeamLine *beamline;
+	      if(particle->Eta >0) beamline = beamline1;
+	      else beamline = beamline2;
+	      
+	      p1.computePath(beamline,1);
+	      
+	      if(p1.stopped(beamline)) {
+		if (p1.getStoppingElement()->getName()=="rp220_1" || p1.getStoppingElement()->getName()=="rp220_2") {
+		  p1.propagate(DET->RP220_S);
+		  elementRP220 = (TRootRomanPotHits*) branchRP220->NewEntry();
+		  elementRP220->X  = (1E-6)*p1.getX();  // [m]
+		  elementRP220->Y  = (1E-6)*p1.getY();  // [m]
+		  elementRP220->Tx = (1E-6)*p1.getTX(); // [rad]
+		  elementRP220->Ty = (1E-6)*p1.getTY(); // [rad]
+		  elementRP220->S = p1.getS();          // [m]
+		  elementRP220->T = -1; 		// not yet implemented
+		  elementRP220->E = p1.getE(); 	// not yet implemented
+		  elementRP220->q2 = -1; 		// not yet implemented
+		  elementRP220->side = sign(particle->Eta); 
+		  
+		} else if (p1.getStoppingElement()->getName()=="rp420_1" || p1.getStoppingElement()->getName()=="rp420_2") {
+		  p1.propagate(DET->FP420_S);
+		  elementFP420 = (TRootRomanPotHits*) branchFP420->NewEntry();
+		  elementFP420->X  = (1E-6)*p1.getX();  // [m]
+		  elementFP420->Y  = (1E-6)*p1.getY();  // [m]
+		  elementFP420->Tx = (1E-6)*p1.getTX(); // [rad]
+		  elementFP420->Ty = (1E-6)*p1.getTY(); // [rad]
+		  elementFP420->S = p1.getS();	      // [m]
+		  elementFP420->T = -1; 		      // not yet implemented
+		  elementFP420->E = p1.getE();          // not yet implemented
+		  elementFP420->q2 = -1;                // not yet implemented
+		  elementFP420->side = sign(particle->Eta);
 		}
-
-//		if(p1.stopped(beamline) && (p1.getStoppingElement()->getS() > 100))
-//			cout << "Eloss ="  << 7000.-p1.getE() << " ; " << p1.getStoppingElement()->getName() << endl;
+	      }
+	      
+	      //		if(p1.stopped(beamline) && (p1.getStoppingElement()->getS() > 100))
+	      //			cout << "Eloss ="  << 7000.-p1.getE() << " ; " << p1.getStoppingElement()->getName() << endl;
 	    } // if forward proton
-
+	  
 	} // while
-
+      
       // computes the Missing Transverse Momentum
       elementEtmis = (TRootETmis*) branchETmis->NewEntry();
@@ -384,56 +405,96 @@
       elementEtmis->Px = (-PTmis).Px();
       elementEtmis->Py = (-PTmis).Py();
-
+      
       //*****************************
-      jets.clear();
+
+      // we will have four jet definitions, and the first three will be
+      // plugins
+      fastjet::JetDefinition jet_def;
+      fastjet::JetDefinition::Plugin * plugins;
+      
       switch(DET->JETALGO) {
-	default:
-	case 1: {
-	    JetCluAlgorithm jetAlgoC(DET->C_SEEDTHRESHOLD,DET->CONERADIUS,DET->C_ADJACENCYCUT,DET->C_MAXITERATIONS,DET->C_IRATCH,DET->C_OVERLAPTHRESHOLD);
-	    jetAlgoC.run(towers, jets);
-	  } 
-	  break;
-
-        case 2: {
-	    MidPointAlgorithm jetAlgoM(DET->M_SEEDTHRESHOLD,DET->CONERADIUS,DET->M_CONEAREAFRACTION,DET->M_MAXPAIRSIZE,DET->M_MAXITERATIONS,DET->M_OVERLAPTHRESHOLD);
-	    jetAlgoM.run(towers, jets);
-	  }
-	  break;
-/*
-	case 3: {
-		FastJet
-  	  }
-	  break;
-*/
-       } // switch
-
-      // Loop on all jets
-      // Dealing with jets, tau-jets, b-jets
-      vector<Cluster>::iterator itJet;
-      for(itJet = jets.begin(); itJet != jets.end(); ++itJet) {
-	  elementJet = (TRootJet*) branchJet->NewEntry();
-          jetMomentum = itJet->fourVector;
-          TLorentzVector JET;
-          JET.SetPxPyPzE(jetMomentum.px,jetMomentum.py,jetMomentum.pz,jetMomentum.E);
-	  elementJet->Set(JET);
-         
-	  // b-jets 
-          bool btag=false;
-          if((fabs(JET.Eta()) < DET->MAX_TRACKER && DET->Btaggedjet(JET, NFCentralQ)))btag=true;
-          elementJet->Btag = btag;
-
-          // Tau jet identification : 1! track and electromagnetic collimation
-	  if(fabs(JET.Eta()) < (DET->MAX_TRACKER - DET->TAU_CONE_TRACKS)) {
-	      double Energie_tau_central = DET->EnergySmallCone(towers,JET.Eta(),JET.Phi());
-	      if( 
-		  ( Energie_tau_central/JET.E() > DET->TAU_EM_COLLIMATION ) &&
-		  ( DET->NumTracks(TrackCentral,DET->PT_TRACK_TAU,JET.Eta(),JET.Phi()) == 1 )
-                ) {
-		  elementTauJet = (TRootTauJet*) branchTauJet->NewEntry();
-		  elementTauJet->Set(JET);
-	       } // if tau jet
-	  } // if JET.eta < tracker - tau_cone : Tau jet identification
-	} // for itJet : loop on all jets
-
+      default:
+      case 1: {
+	
+	// set up a CDF midpoint jet definition
+        #ifdef ENABLE_PLUGIN_CDFCONES
+	plugins = new fastjet::CDFJetCluPlugin(DET->C_SEEDTHRESHOLD,DET->CONERADIUS,DET->C_ADJACENCYCUT,DET->C_MAXITERATIONS,DET->C_IRATCH,DET->C_OVERLAPTHRESHOLD);
+	jet_def = fastjet::JetDefinition(plugins);
+        #else
+	plugins = NULL;
+        #endif
+	
+      } 
+	break;
+	
+      case 2: {
+	
+        // set up a CDF midpoint jet definition
+        #ifdef ENABLE_PLUGIN_CDFCONES
+        plugins = new fastjet::CDFMidPointPlugin (DET->M_SEEDTHRESHOLD,DET->CONERADIUS,DET->M_CONEAREAFRACTION,DET->M_MAXPAIRSIZE,DET->M_MAXPAIRSIZE,DET->C_OVERLAPTHRESHOLD);
+	jet_def = fastjet::JetDefinition(plugins);
+        #else
+	plugins = NULL;
+        #endif
+      }
+	break;
+	
+      case 3: {
+	// set up a siscone jet definition
+        #ifdef ENABLE_PLUGIN_SISCONE
+	int npass = 0;               // do infinite number of passes
+	double protojet_ptmin = 0.0; // use all protojets
+	plugins = new fastjet::SISConePlugin (DET->CONERADIUS,DET->C_OVERLAPTHRESHOLD,npass, protojet_ptmin);
+	jet_def = fastjet::JetDefinition(plugins);
+        #else
+        plugins = NULL;
+        #endif
+      }
+        break; 
+	
+      case 4: {
+        jet_def = fastjet::JetDefinition(fastjet::kt_algorithm, DET->CONERADIUS);
+        //jet_defs[4] = fastjet::JetDefinition(fastjet::cambridge_algorithm,jet_radius);
+        //jet_defs[5] = fastjet::JetDefinition(fastjet::antikt_algorithm,jet_radius);
+      }
+        break;
+      }
+      // run the jet clustering with the above jet definition
+      if(input_particles.size()!=0)
+	{
+	  fastjet::ClusterSequence clust_seq(input_particles, jet_def);
+	  
+	  
+	  // extract the inclusive jets with pt > 5 GeV
+	  double ptmin = 5.0;
+	  inclusive_jets = clust_seq.inclusive_jets(ptmin);
+	  
+	  // sort jets into increasing pt
+	  sorted_by_pt(inclusive_jets);
+	}
+      
+      for (unsigned int i = 0; i < inclusive_jets.size(); i++) {
+	elementJet = (TRootJet*) branchJet->NewEntry();
+	TLorentzVector JET;
+	JET.SetPxPyPzE(inclusive_jets[i].px(),inclusive_jets[i].py(),inclusive_jets[i].pz(),inclusive_jets[i].E());
+	elementJet->Set(JET);
+	// b-jets
+	bool btag=false;
+	if((fabs(JET.Eta()) < DET->MAX_TRACKER && DET->Btaggedjet(JET, NFCentralQ)))btag=true;
+	elementJet->Btag = btag;
+	
+	// Tau jet identification : 1! track and electromagnetic collimation
+	if(fabs(JET.Eta()) < (DET->MAX_TRACKER - DET->TAU_CONE_TRACKS)) {
+	  double Energie_tau_central = DET->EnergySmallCone(towers,JET.Eta(),JET.Phi());
+	  if(
+	     ( Energie_tau_central/JET.E() > DET->TAU_EM_COLLIMATION ) &&
+	     ( DET->NumTracks(TrackCentral,DET->PT_TRACK_TAU,JET.Eta(),JET.Phi()) == 1 )
+	     ) {
+	    elementTauJet = (TRootTauJet*) branchTauJet->NewEntry();
+	    elementTauJet->Set(JET);
+	  } // if tau jet
+	} // if JET.eta < tracker - tau_cone : Tau jet identification
+      } // for itJet : loop on all jets
+      
       treeWriter->Fill();
       // Add here the trigger
Index: /trunk/Makefile
===================================================================
--- /trunk/Makefile	(revision 10)
+++ /trunk/Makefile	(revision 11)
@@ -28,22 +28,4 @@
 
 
-Resolutions$(ExeSuf): \
-	tmp/Resolutions.$(ObjSuf)
-
-tmp/Resolutions.$(ObjSuf): \
-	Resolutions.cpp \
-	Utilities/ExRootAnalysis/interface/ExRootTreeReader.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h \
-	Utilities/CDFCones/interface/JetCluAlgorithm.h \
-	Utilities/CDFCones/interface/MidPointAlgorithm.h \
-	Utilities/CDFCones/interface/PhysicsTower.h \
-	Utilities/CDFCones/interface/Cluster.h \
-	interface/DataConverter.h \
-	interface/HEPEVTConverter.h \
-	interface/LHEFConverter.h \
-	interface/STDHEPConverter.h \
-	interface/SmearUtil.h \
-	interface/TreeClasses.h
 Delphes$(ExeSuf): \
 	tmp/Delphes.$(ObjSuf)
@@ -54,8 +36,4 @@
 	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
 	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h \
-	Utilities/CDFCones/interface/JetCluAlgorithm.h \
-	Utilities/CDFCones/interface/MidPointAlgorithm.h \
-	Utilities/CDFCones/interface/PhysicsTower.h \
-	Utilities/CDFCones/interface/Cluster.h \
 	interface/DataConverter.h \
 	interface/HEPEVTConverter.h \
@@ -64,9 +42,7 @@
 	interface/SmearUtil.h
 EXECUTABLE =  \
-	Resolutions$(ExeSuf) \
 	Delphes$(ExeSuf)
 
 EXECUTABLE_OBJ =  \
-	tmp/Resolutions.$(ObjSuf) \
 	tmp/Delphes.$(ObjSuf)
 
@@ -74,14 +50,24 @@
 	Utilities/ExRootAnalysis/src/BlockClassesLinkDef.h \
 	Utilities/ExRootAnalysis/interface/BlockClasses.h
-tmp/src/TreeClassesDict.$(SrcSuf): \
-	src/TreeClassesLinkDef.h
 DICT =  \
-	tmp/Utilities/ExRootAnalysis/src/BlockClassesDict.$(SrcSuf) \
-	tmp/src/TreeClassesDict.$(SrcSuf)
+	tmp/Utilities/ExRootAnalysis/src/BlockClassesDict.$(SrcSuf)
 
 DICT_OBJ =  \
-	tmp/Utilities/ExRootAnalysis/src/BlockClassesDict.$(ObjSuf) \
-	tmp/src/TreeClassesDict.$(ObjSuf)
-
+	tmp/Utilities/ExRootAnalysis/src/BlockClassesDict.$(ObjSuf)
+
+tmp/src/HEPEVTConverter.$(ObjSuf): \
+	src/HEPEVTConverter.$(SrcSuf) \
+	Utilities/ExRootAnalysis/interface/BlockClasses.h \
+	Utilities/ExRootAnalysis/interface/ExRootTreeReader.h \
+	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
+	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h \
+	interface/HEPEVTConverter.h
+tmp/src/LHEFConverter.$(ObjSuf): \
+	src/LHEFConverter.$(SrcSuf) \
+	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
+	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h \
+	Utilities/ExRootAnalysis/interface/BlockClasses.h \
+	interface/LHEFConverter.h \
+	Utilities/ExRootAnalysis/interface/LHEF.h
 tmp/src/STDHEPConverter.$(ObjSuf): \
 	src/STDHEPConverter.$(SrcSuf) \
@@ -94,32 +80,14 @@
 	Utilities/stdhep/stdhep_declarations.h \
 	interface/STDHEPConverter.h
-tmp/src/TreeClasses.$(ObjSuf): \
-	src/TreeClasses.$(SrcSuf) \
-	interface/TreeClasses.h
-tmp/src/LHEFConverter.$(ObjSuf): \
-	src/LHEFConverter.$(SrcSuf) \
-	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h \
-	Utilities/ExRootAnalysis/interface/BlockClasses.h \
-	interface/LHEFConverter.h \
-	Utilities/ExRootAnalysis/interface/LHEF.h
-tmp/src/HEPEVTConverter.$(ObjSuf): \
-	src/HEPEVTConverter.$(SrcSuf) \
-	Utilities/ExRootAnalysis/interface/BlockClasses.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeReader.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h \
-	interface/HEPEVTConverter.h
 tmp/src/SmearUtil.$(ObjSuf): \
 	src/SmearUtil.$(SrcSuf) \
 	interface/SmearUtil.h
-tmp/Utilities/ExRootAnalysis/src/ExRootTreeWriter.$(ObjSuf): \
-	Utilities/ExRootAnalysis/src/ExRootTreeWriter.$(SrcSuf) \
-	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
-	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h
 tmp/Utilities/ExRootAnalysis/src/BlockClasses.$(ObjSuf): \
 	Utilities/ExRootAnalysis/src/BlockClasses.$(SrcSuf) \
 	Utilities/ExRootAnalysis/interface/BlockClasses.h \
 	Utilities/ExRootAnalysis/interface/BlockCompare.h
+tmp/Utilities/ExRootAnalysis/src/ExRootProgressBar.$(ObjSuf): \
+	Utilities/ExRootAnalysis/src/ExRootProgressBar.$(SrcSuf) \
+	Utilities/ExRootAnalysis/interface/ExRootProgressBar.h
 tmp/Utilities/ExRootAnalysis/src/ExRootTreeBranch.$(ObjSuf): \
 	Utilities/ExRootAnalysis/src/ExRootTreeBranch.$(SrcSuf) \
@@ -128,131 +96,281 @@
 	Utilities/ExRootAnalysis/src/ExRootTreeReader.$(SrcSuf) \
 	Utilities/ExRootAnalysis/interface/ExRootTreeReader.h
-tmp/Utilities/ExRootAnalysis/src/ExRootProgressBar.$(ObjSuf): \
-	Utilities/ExRootAnalysis/src/ExRootProgressBar.$(SrcSuf) \
-	Utilities/ExRootAnalysis/interface/ExRootProgressBar.h
-tmp/Utilities/Hector/src/H_Parameters.$(ObjSuf): \
-	Utilities/Hector/src/H_Parameters.$(SrcSuf)
-tmp/Utilities/Hector/src/H_RomanPot.$(ObjSuf): \
-	Utilities/Hector/src/H_RomanPot.$(SrcSuf)
-tmp/Utilities/Hector/src/H_Beam.$(ObjSuf): \
-	Utilities/Hector/src/H_Beam.$(SrcSuf)
-tmp/Utilities/Hector/src/H_SectorDipole.$(ObjSuf): \
-	Utilities/Hector/src/H_SectorDipole.$(SrcSuf)
-tmp/Utilities/Hector/src/H_RecRPObject.$(ObjSuf): \
-	Utilities/Hector/src/H_RecRPObject.$(SrcSuf)
-tmp/Utilities/Hector/src/H_Drift.$(ObjSuf): \
-	Utilities/Hector/src/H_Drift.$(SrcSuf)
-tmp/Utilities/Hector/src/H_CircularAperture.$(ObjSuf): \
-	Utilities/Hector/src/H_CircularAperture.$(SrcSuf)
-tmp/Utilities/Hector/src/H_VerticalQuadrupole.$(ObjSuf): \
-	Utilities/Hector/src/H_VerticalQuadrupole.$(SrcSuf)
-tmp/Utilities/Hector/src/H_EllipticAperture.$(ObjSuf): \
-	Utilities/Hector/src/H_EllipticAperture.$(SrcSuf)
-tmp/Utilities/Hector/src/H_RectangularDipole.$(ObjSuf): \
-	Utilities/Hector/src/H_RectangularDipole.$(SrcSuf)
-tmp/Utilities/Hector/src/H_OpticalElement.$(ObjSuf): \
-	Utilities/Hector/src/H_OpticalElement.$(SrcSuf)
-tmp/Utilities/Hector/src/H_Kicker.$(ObjSuf): \
-	Utilities/Hector/src/H_Kicker.$(SrcSuf)
-tmp/Utilities/Hector/src/H_BeamLineParser.$(ObjSuf): \
-	Utilities/Hector/src/H_BeamLineParser.$(SrcSuf)
+tmp/Utilities/ExRootAnalysis/src/ExRootTreeWriter.$(ObjSuf): \
+	Utilities/ExRootAnalysis/src/ExRootTreeWriter.$(SrcSuf) \
+	Utilities/ExRootAnalysis/interface/ExRootTreeWriter.h \
+	Utilities/ExRootAnalysis/interface/ExRootTreeBranch.h
 tmp/Utilities/Hector/src/H_AbstractBeamLine.$(ObjSuf): \
 	Utilities/Hector/src/H_AbstractBeamLine.$(SrcSuf)
 tmp/Utilities/Hector/src/H_Aperture.$(ObjSuf): \
 	Utilities/Hector/src/H_Aperture.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Beam.$(ObjSuf): \
+	Utilities/Hector/src/H_Beam.$(SrcSuf)
+tmp/Utilities/Hector/src/H_BeamLine.$(ObjSuf): \
+	Utilities/Hector/src/H_BeamLine.$(SrcSuf)
+tmp/Utilities/Hector/src/H_BeamLineParser.$(ObjSuf): \
+	Utilities/Hector/src/H_BeamLineParser.$(SrcSuf)
 tmp/Utilities/Hector/src/H_BeamParticle.$(ObjSuf): \
 	Utilities/Hector/src/H_BeamParticle.$(SrcSuf)
+tmp/Utilities/Hector/src/H_CircularAperture.$(ObjSuf): \
+	Utilities/Hector/src/H_CircularAperture.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Dipole.$(ObjSuf): \
+	Utilities/Hector/src/H_Dipole.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Drift.$(ObjSuf): \
+	Utilities/Hector/src/H_Drift.$(SrcSuf)
+tmp/Utilities/Hector/src/H_EllipticAperture.$(ObjSuf): \
+	Utilities/Hector/src/H_EllipticAperture.$(SrcSuf)
+tmp/Utilities/Hector/src/H_HorizontalKicker.$(ObjSuf): \
+	Utilities/Hector/src/H_HorizontalKicker.$(SrcSuf)
+tmp/Utilities/Hector/src/H_HorizontalQuadrupole.$(ObjSuf): \
+	Utilities/Hector/src/H_HorizontalQuadrupole.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Kicker.$(ObjSuf): \
+	Utilities/Hector/src/H_Kicker.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Marker.$(ObjSuf): \
+	Utilities/Hector/src/H_Marker.$(SrcSuf)
+tmp/Utilities/Hector/src/H_OpticalElement.$(ObjSuf): \
+	Utilities/Hector/src/H_OpticalElement.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Parameters.$(ObjSuf): \
+	Utilities/Hector/src/H_Parameters.$(SrcSuf)
+tmp/Utilities/Hector/src/H_Quadrupole.$(ObjSuf): \
+	Utilities/Hector/src/H_Quadrupole.$(SrcSuf)
+tmp/Utilities/Hector/src/H_RecRPObject.$(ObjSuf): \
+	Utilities/Hector/src/H_RecRPObject.$(SrcSuf)
+tmp/Utilities/Hector/src/H_RectEllipticAperture.$(ObjSuf): \
+	Utilities/Hector/src/H_RectEllipticAperture.$(SrcSuf)
+tmp/Utilities/Hector/src/H_RectangularAperture.$(ObjSuf): \
+	Utilities/Hector/src/H_RectangularAperture.$(SrcSuf)
+tmp/Utilities/Hector/src/H_RectangularCollimator.$(ObjSuf): \
+	Utilities/Hector/src/H_RectangularCollimator.$(SrcSuf)
+tmp/Utilities/Hector/src/H_RectangularDipole.$(ObjSuf): \
+	Utilities/Hector/src/H_RectangularDipole.$(SrcSuf)
+tmp/Utilities/Hector/src/H_RomanPot.$(ObjSuf): \
+	Utilities/Hector/src/H_RomanPot.$(SrcSuf)
+tmp/Utilities/Hector/src/H_SectorDipole.$(ObjSuf): \
+	Utilities/Hector/src/H_SectorDipole.$(SrcSuf)
 tmp/Utilities/Hector/src/H_TransportMatrices.$(ObjSuf): \
 	Utilities/Hector/src/H_TransportMatrices.$(SrcSuf)
-tmp/Utilities/Hector/src/H_HorizontalKicker.$(ObjSuf): \
-	Utilities/Hector/src/H_HorizontalKicker.$(SrcSuf)
-tmp/Utilities/Hector/src/H_Quadrupole.$(ObjSuf): \
-	Utilities/Hector/src/H_Quadrupole.$(SrcSuf)
-tmp/Utilities/Hector/src/H_RectangularAperture.$(ObjSuf): \
-	Utilities/Hector/src/H_RectangularAperture.$(SrcSuf)
-tmp/Utilities/Hector/src/H_Marker.$(ObjSuf): \
-	Utilities/Hector/src/H_Marker.$(SrcSuf)
-tmp/Utilities/Hector/src/H_RectangularCollimator.$(ObjSuf): \
-	Utilities/Hector/src/H_RectangularCollimator.$(SrcSuf)
-tmp/Utilities/Hector/src/H_BeamLine.$(ObjSuf): \
-	Utilities/Hector/src/H_BeamLine.$(SrcSuf)
-tmp/Utilities/Hector/src/H_HorizontalQuadrupole.$(ObjSuf): \
-	Utilities/Hector/src/H_HorizontalQuadrupole.$(SrcSuf)
 tmp/Utilities/Hector/src/H_VerticalKicker.$(ObjSuf): \
 	Utilities/Hector/src/H_VerticalKicker.$(SrcSuf)
-tmp/Utilities/Hector/src/H_RectEllipticAperture.$(ObjSuf): \
-	Utilities/Hector/src/H_RectEllipticAperture.$(SrcSuf)
-tmp/Utilities/Hector/src/H_Dipole.$(ObjSuf): \
-	Utilities/Hector/src/H_Dipole.$(SrcSuf)
-tmp/Utilities/CDFCones/src/MidPointAlgorithm.$(ObjSuf): \
-	Utilities/CDFCones/src/MidPointAlgorithm.$(SrcSuf) \
-	Utilities/CDFCones/interface/MidPointAlgorithm.h \
-	Utilities/CDFCones/interface/ClusterComparisons.h
-tmp/Utilities/CDFCones/src/JetCluAlgorithm.$(ObjSuf): \
-	Utilities/CDFCones/src/JetCluAlgorithm.$(SrcSuf) \
-	Utilities/CDFCones/interface/JetCluAlgorithm.h \
-	Utilities/CDFCones/interface/ClusterComparisons.h \
-	Utilities/CDFCones/interface/Centroid.h
+tmp/Utilities/Hector/src/H_VerticalQuadrupole.$(ObjSuf): \
+	Utilities/Hector/src/H_VerticalQuadrupole.$(SrcSuf)
+tmp/Utilities/Fastjet/src/DnnPlane.$(ObjSuf): \
+	Utilities/Fastjet/src/DnnPlane.$(SrcSuf)
+tmp/Utilities/Fastjet/src/Dnn4piCylinder.$(ObjSuf): \
+	Utilities/Fastjet/src/Dnn4piCylinder.$(SrcSuf)
+tmp/Utilities/Fastjet/src/Dnn3piCylinder.$(ObjSuf): \
+	Utilities/Fastjet/src/Dnn3piCylinder.$(SrcSuf)
+tmp/Utilities/Fastjet/src/Dnn2piCylinder.$(ObjSuf): \
+	Utilities/Fastjet/src/Dnn2piCylinder.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence.$(SrcSuf)
+tmp/Utilities/Fastjet/src/PseudoJet.$(ObjSuf): \
+	Utilities/Fastjet/src/PseudoJet.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence_N2.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence_N2.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence_TiledN2.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence_TiledN2.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence_Delaunay.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence_Delaunay.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence_DumbN3.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence_DumbN3.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence_CP2DChan.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence_CP2DChan.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClosestPair2D.$(ObjSuf): \
+	Utilities/Fastjet/src/ClosestPair2D.$(SrcSuf)
+tmp/Utilities/Fastjet/src/MinHeap.$(ObjSuf): \
+	Utilities/Fastjet/src/MinHeap.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequenceAreaBase.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequenceAreaBase.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequenceActiveAreaExplicitGhosts.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequenceActiveAreaExplicitGhosts.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequenceArea.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequenceArea.$(SrcSuf)
+tmp/Utilities/Fastjet/src/GhostedAreaSpec.$(ObjSuf): \
+	Utilities/Fastjet/src/GhostedAreaSpec.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequenceActiveArea.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequenceActiveArea.$(SrcSuf)
+tmp/Utilities/Fastjet/src/Voronoi.$(ObjSuf): \
+	Utilities/Fastjet/src/Voronoi.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequenceVoronoiArea.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequenceVoronoiArea.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequencePassiveArea.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequencePassiveArea.$(SrcSuf)
+tmp/Utilities/Fastjet/src/ClusterSequence1GhostPassiveArea.$(ObjSuf): \
+	Utilities/Fastjet/src/ClusterSequence1GhostPassiveArea.$(SrcSuf)
+tmp/Utilities/Fastjet/src/BasicRandom.$(ObjSuf): \
+	Utilities/Fastjet/src/BasicRandom.$(SrcSuf)
+tmp/Utilities/Fastjet/src/JetDefinition.$(ObjSuf): \
+	Utilities/Fastjet/src/JetDefinition.$(SrcSuf)
+tmp/Utilities/Fastjet/src/Error.$(ObjSuf): \
+	Utilities/Fastjet/src/Error.$(SrcSuf)
+tmp/Utilities/Fastjet/src/AreaDefinition.$(ObjSuf): \
+	Utilities/Fastjet/src/AreaDefinition.$(SrcSuf)
+tmp/Utilities/Fastjet/src/RangeDefinition.$(ObjSuf): \
+	Utilities/Fastjet/src/RangeDefinition.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.$(SrcSuf) \
+	Utilities/Fastjet/include/fastjet/ClusterSequence.hh
+tmp/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.$(SrcSuf) \
+	Utilities/Fastjet/include/fastjet/ClusterSequence.hh \
+	Utilities/Fastjet/include/fastjet/Error.hh
+tmp/Utilities/Fastjet/plugins/CDFCones/src/CalTower.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/CalTower.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/Centroid.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/Centroid.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/Cluster.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/Cluster.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/ClusterComparisons.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/ClusterComparisons.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/JetCluAlgorithm.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/JetCluAlgorithm.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/LorentzVector.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/LorentzVector.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/MidPointAlgorithm.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/MidPointAlgorithm.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/CDFCones/src/PhysicsTower.$(ObjSuf): \
+	Utilities/Fastjet/plugins/CDFCones/src/PhysicsTower.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/SISConePlugin.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/SISConePlugin.$(SrcSuf) \
+	Utilities/Fastjet/include/fastjet/ClusterSequence.hh
+tmp/Utilities/Fastjet/plugins/SISCone/src/area.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/area.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/geom_2d.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/geom_2d.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/hash.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/hash.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/momentum.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/momentum.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/protocones.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/protocones.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/quadtree.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/quadtree.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/ranlux.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/ranlux.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/reference.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/reference.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/siscone.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/siscone.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/siscone_error.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/siscone_error.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/split_merge.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/split_merge.$(SrcSuf)
+tmp/Utilities/Fastjet/plugins/SISCone/src/vicinity.$(ObjSuf): \
+	Utilities/Fastjet/plugins/SISCone/src/vicinity.$(SrcSuf)
 SOURCE_OBJ =  \
+	tmp/src/HEPEVTConverter.$(ObjSuf) \
+	tmp/src/LHEFConverter.$(ObjSuf) \
 	tmp/src/STDHEPConverter.$(ObjSuf) \
-	tmp/src/TreeClasses.$(ObjSuf) \
-	tmp/src/LHEFConverter.$(ObjSuf) \
-	tmp/src/HEPEVTConverter.$(ObjSuf) \
 	tmp/src/SmearUtil.$(ObjSuf) \
-	tmp/Utilities/ExRootAnalysis/src/ExRootTreeWriter.$(ObjSuf) \
 	tmp/Utilities/ExRootAnalysis/src/BlockClasses.$(ObjSuf) \
+	tmp/Utilities/ExRootAnalysis/src/ExRootProgressBar.$(ObjSuf) \
 	tmp/Utilities/ExRootAnalysis/src/ExRootTreeBranch.$(ObjSuf) \
 	tmp/Utilities/ExRootAnalysis/src/ExRootTreeReader.$(ObjSuf) \
-	tmp/Utilities/ExRootAnalysis/src/ExRootProgressBar.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Parameters.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_RomanPot.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Beam.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_SectorDipole.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_RecRPObject.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Drift.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_CircularAperture.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_VerticalQuadrupole.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_EllipticAperture.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_RectangularDipole.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_OpticalElement.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Kicker.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_BeamLineParser.$(ObjSuf) \
+	tmp/Utilities/ExRootAnalysis/src/ExRootTreeWriter.$(ObjSuf) \
 	tmp/Utilities/Hector/src/H_AbstractBeamLine.$(ObjSuf) \
 	tmp/Utilities/Hector/src/H_Aperture.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Beam.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_BeamLine.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_BeamLineParser.$(ObjSuf) \
 	tmp/Utilities/Hector/src/H_BeamParticle.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_CircularAperture.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Dipole.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Drift.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_EllipticAperture.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_HorizontalKicker.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_HorizontalQuadrupole.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Kicker.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Marker.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_OpticalElement.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Parameters.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_Quadrupole.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_RecRPObject.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_RectEllipticAperture.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_RectangularAperture.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_RectangularCollimator.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_RectangularDipole.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_RomanPot.$(ObjSuf) \
+	tmp/Utilities/Hector/src/H_SectorDipole.$(ObjSuf) \
 	tmp/Utilities/Hector/src/H_TransportMatrices.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_HorizontalKicker.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Quadrupole.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_RectangularAperture.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Marker.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_RectangularCollimator.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_BeamLine.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_HorizontalQuadrupole.$(ObjSuf) \
 	tmp/Utilities/Hector/src/H_VerticalKicker.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_RectEllipticAperture.$(ObjSuf) \
-	tmp/Utilities/Hector/src/H_Dipole.$(ObjSuf) \
-	tmp/Utilities/CDFCones/src/MidPointAlgorithm.$(ObjSuf) \
-	tmp/Utilities/CDFCones/src/JetCluAlgorithm.$(ObjSuf)
-
+	tmp/Utilities/Hector/src/H_VerticalQuadrupole.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/DnnPlane.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/Dnn4piCylinder.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/Dnn3piCylinder.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/Dnn2piCylinder.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/PseudoJet.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence_N2.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence_TiledN2.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence_Delaunay.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence_DumbN3.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence_CP2DChan.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClosestPair2D.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/MinHeap.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequenceAreaBase.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequenceActiveAreaExplicitGhosts.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequenceArea.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/GhostedAreaSpec.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequenceActiveArea.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/Voronoi.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequenceVoronoiArea.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequencePassiveArea.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/ClusterSequence1GhostPassiveArea.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/BasicRandom.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/JetDefinition.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/Error.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/AreaDefinition.$(ObjSuf) \
+	tmp/Utilities/Fastjet/src/RangeDefinition.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/CalTower.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/Centroid.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/Cluster.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/ClusterComparisons.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/JetCluAlgorithm.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/LorentzVector.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/MidPointAlgorithm.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/CDFCones/src/PhysicsTower.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/SISConePlugin.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/area.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/geom_2d.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/hash.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/momentum.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/protocones.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/quadtree.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/ranlux.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/reference.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/siscone.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/siscone_error.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/split_merge.$(ObjSuf) \
+	tmp/Utilities/Fastjet/plugins/SISCone/src/vicinity.$(ObjSuf)
+
+tmp/Utilities/mcfio/mcf_NTuIOFiles.$(ObjSuf): \
+	Utilities/mcfio/mcf_NTuIOFiles.c
+tmp/Utilities/mcfio/mcf_NTuIOUtils.$(ObjSuf): \
+	Utilities/mcfio/mcf_NTuIOUtils.c
+tmp/Utilities/mcfio/mcf_evt_xdr.$(ObjSuf): \
+	Utilities/mcfio/mcf_evt_xdr.c
 tmp/Utilities/mcfio/mcf_ntuBldDbinc.$(ObjSuf): \
 	Utilities/mcfio/mcf_ntuBldDbinc.c
-tmp/Utilities/mcfio/mcfio_SeqDummy.$(ObjSuf): \
-	Utilities/mcfio/mcfio_SeqDummy.c
-tmp/Utilities/mcfio/mcfio_Util1.$(ObjSuf): \
-	Utilities/mcfio/mcfio_Util1.c
-tmp/Utilities/mcfio/mcf_evt_xdr.$(ObjSuf): \
-	Utilities/mcfio/mcf_evt_xdr.c
-tmp/Utilities/mcfio/mcf_NTuIOUtils.$(ObjSuf): \
-	Utilities/mcfio/mcf_NTuIOUtils.c
+tmp/Utilities/mcfio/mcf_ntubldInit.$(ObjSuf): \
+	Utilities/mcfio/mcf_ntubldInit.c
 tmp/Utilities/mcfio/mcfio_Block.$(ObjSuf): \
 	Utilities/mcfio/mcfio_Block.c
 tmp/Utilities/mcfio/mcfio_Direct.$(ObjSuf): \
 	Utilities/mcfio/mcfio_Direct.c
-tmp/Utilities/mcfio/mcf_NTuIOFiles.$(ObjSuf): \
-	Utilities/mcfio/mcf_NTuIOFiles.c
+tmp/Utilities/mcfio/mcfio_SeqDummy.$(ObjSuf): \
+	Utilities/mcfio/mcfio_SeqDummy.c
 tmp/Utilities/mcfio/mcfio_UserDictionary.$(ObjSuf): \
 	Utilities/mcfio/mcfio_UserDictionary.c
-tmp/Utilities/mcfio/mcf_ntubldInit.$(ObjSuf): \
-	Utilities/mcfio/mcf_ntubldInit.c
+tmp/Utilities/mcfio/mcfio_Util1.$(ObjSuf): \
+	Utilities/mcfio/mcfio_Util1.c
+tmp/Utilities/stdhep/mcf_Stdhep_xdr.$(ObjSuf): \
+	Utilities/stdhep/mcf_Stdhep_xdr.c \
+	Utilities/mcfio/mcfio_Dict.h \
+	Utilities/mcfio/mcf_xdr.h \
+	Utilities/stdhep/stdhep.h \
+	Utilities/stdhep/stdtmp.h \
+	Utilities/stdhep/stdver.h
 tmp/Utilities/stdhep/mcf_hepev4_xdr.$(ObjSuf): \
 	Utilities/stdhep/mcf_hepev4_xdr.c \
@@ -263,10 +381,4 @@
 	Utilities/stdhep/stdtmp.h \
 	Utilities/stdhep/stdver.h
-tmp/Utilities/stdhep/mcf_stdcm1_xdr.$(ObjSuf): \
-	Utilities/stdhep/mcf_stdcm1_xdr.c \
-	Utilities/mcfio/mcfio_Dict.h \
-	Utilities/mcfio/mcf_xdr.h \
-	Utilities/stdhep/stdcm1.h \
-	Utilities/stdhep/stdver.h
 tmp/Utilities/stdhep/mcf_hepup_xdr.$(ObjSuf): \
 	Utilities/stdhep/mcf_hepup_xdr.c \
@@ -276,10 +388,9 @@
 	Utilities/stdhep/heprup.h \
 	Utilities/stdhep/stdver.h
-tmp/Utilities/stdhep/mcf_Stdhep_xdr.$(ObjSuf): \
-	Utilities/stdhep/mcf_Stdhep_xdr.c \
+tmp/Utilities/stdhep/mcf_stdcm1_xdr.$(ObjSuf): \
+	Utilities/stdhep/mcf_stdcm1_xdr.c \
 	Utilities/mcfio/mcfio_Dict.h \
 	Utilities/mcfio/mcf_xdr.h \
-	Utilities/stdhep/stdhep.h \
-	Utilities/stdhep/stdtmp.h \
+	Utilities/stdhep/stdcm1.h \
 	Utilities/stdhep/stdver.h
 tmp/Utilities/stdhep/stdhep_internal_utils.$(ObjSuf): \
@@ -305,25 +416,20 @@
 	Utilities/stdhep/stdhep_mcfio.h
 STDHEP_OBJ =  \
+	tmp/Utilities/mcfio/mcf_NTuIOFiles.$(ObjSuf) \
+	tmp/Utilities/mcfio/mcf_NTuIOUtils.$(ObjSuf) \
+	tmp/Utilities/mcfio/mcf_evt_xdr.$(ObjSuf) \
 	tmp/Utilities/mcfio/mcf_ntuBldDbinc.$(ObjSuf) \
-	tmp/Utilities/mcfio/mcfio_SeqDummy.$(ObjSuf) \
-	tmp/Utilities/mcfio/mcfio_Util1.$(ObjSuf) \
-	tmp/Utilities/mcfio/mcf_evt_xdr.$(ObjSuf) \
-	tmp/Utilities/mcfio/mcf_NTuIOUtils.$(ObjSuf) \
+	tmp/Utilities/mcfio/mcf_ntubldInit.$(ObjSuf) \
 	tmp/Utilities/mcfio/mcfio_Block.$(ObjSuf) \
 	tmp/Utilities/mcfio/mcfio_Direct.$(ObjSuf) \
-	tmp/Utilities/mcfio/mcf_NTuIOFiles.$(ObjSuf) \
+	tmp/Utilities/mcfio/mcfio_SeqDummy.$(ObjSuf) \
 	tmp/Utilities/mcfio/mcfio_UserDictionary.$(ObjSuf) \
-	tmp/Utilities/mcfio/mcf_ntubldInit.$(ObjSuf) \
+	tmp/Utilities/mcfio/mcfio_Util1.$(ObjSuf) \
+	tmp/Utilities/stdhep/mcf_Stdhep_xdr.$(ObjSuf) \
 	tmp/Utilities/stdhep/mcf_hepev4_xdr.$(ObjSuf) \
+	tmp/Utilities/stdhep/mcf_hepup_xdr.$(ObjSuf) \
 	tmp/Utilities/stdhep/mcf_stdcm1_xdr.$(ObjSuf) \
-	tmp/Utilities/stdhep/mcf_hepup_xdr.$(ObjSuf) \
-	tmp/Utilities/stdhep/mcf_Stdhep_xdr.$(ObjSuf) \
 	tmp/Utilities/stdhep/stdhep_internal_utils.$(ObjSuf) \
 	tmp/Utilities/stdhep/stdhep_mcfio.$(ObjSuf)
-
-Utilities/CDFCones/interface/MidPointAlgorithm.h: \
-	Utilities/CDFCones/interface/PhysicsTower.h \
-	Utilities/CDFCones/interface/Cluster.h
-	@touch $@
 
 interface/DataConverter.h: \
@@ -335,17 +441,11 @@
 	Utilities/ExRootAnalysis/interface/BlockClasses.h \
 	Utilities/ExRootAnalysis/interface/TSimpleArray.h \
-	Utilities/CDFCones/interface/PhysicsTower.h \
 	interface/DataConverter.h
 	@touch $@
 
-interface/TreeClasses.h: \
-	Utilities/ExRootAnalysis/interface/BlockCompare.h \
-	Utilities/ExRootAnalysis/interface/BlockClasses.h
-	@touch $@
-
 interface/SmearUtil.h: \
 	Utilities/ExRootAnalysis/interface/BlockClasses.h \
 	Utilities/ExRootAnalysis/interface/TSimpleArray.h \
-	Utilities/CDFCones/interface/PhysicsTower.h
+	Utilities/Fastjet/plugins/CDFCones/interface/PhysicsTower.hh
 	@touch $@
 
@@ -356,8 +456,13 @@
 	@touch $@
 
-Utilities/CDFCones/interface/Cluster.h: \
-	Utilities/CDFCones/interface/PhysicsTower.h \
-	Utilities/CDFCones/interface/LorentzVector.h \
-	Utilities/CDFCones/interface/Centroid.h
+Utilities/Fastjet/include/fastjet/Error.hh: \
+	Utilities/Fastjet/include/fastjet/internal/base.hh
+	@touch $@
+
+Utilities/Fastjet/include/fastjet/ClusterSequence.hh: \
+	Utilities/Fastjet/include/fastjet/internal/DynamicNearestNeighbours.hh \
+	Utilities/Fastjet/include/fastjet/PseudoJet.hh \
+	Utilities/Fastjet/include/fastjet/Error.hh \
+	Utilities/Fastjet/include/fastjet/JetDefinition.hh
 	@touch $@
 
@@ -374,28 +479,13 @@
 	@touch $@
 
-Utilities/CDFCones/interface/PhysicsTower.h: \
-	Utilities/CDFCones/interface/LorentzVector.h \
-	Utilities/CDFCones/interface/CalTower.h
-	@touch $@
-
-Utilities/CDFCones/interface/JetCluAlgorithm.h: \
-	Utilities/CDFCones/interface/PhysicsTower.h \
-	Utilities/CDFCones/interface/Cluster.h
-	@touch $@
-
-Utilities/CDFCones/interface/ClusterComparisons.h: \
-	Utilities/CDFCones/interface/Cluster.h
+interface/STDHEPConverter.h: \
+	Utilities/ExRootAnalysis/interface/BlockClasses.h \
+	Utilities/ExRootAnalysis/interface/TSimpleArray.h \
+	Utilities/ExRootAnalysis/interface/LHEF.h \
+	interface/DataConverter.h
 	@touch $@
 
 Utilities/ExRootAnalysis/interface/BlockClasses.h: \
 	Utilities/ExRootAnalysis/interface/BlockCompare.h
-	@touch $@
-
-interface/STDHEPConverter.h: \
-	Utilities/ExRootAnalysis/interface/BlockClasses.h \
-	Utilities/ExRootAnalysis/interface/TSimpleArray.h \
-	Utilities/CDFCones/interface/PhysicsTower.h \
-	Utilities/ExRootAnalysis/interface/LHEF.h \
-	interface/DataConverter.h
 	@touch $@
 
Index: /trunk/Utilities/Fastjet/CREDITS
===================================================================
--- /trunk/Utilities/Fastjet/CREDITS	(revision 11)
+++ /trunk/Utilities/Fastjet/CREDITS	(revision 11)
@@ -0,0 +1,1 @@
+not available
Index: /trunk/Utilities/Fastjet/VERSION
===================================================================
--- /trunk/Utilities/Fastjet/VERSION	(revision 11)
+++ /trunk/Utilities/Fastjet/VERSION	(revision 11)
@@ -0,0 +1,1 @@
+2.3.4
Index: /trunk/Utilities/Fastjet/include/FjClusterSequence.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/FjClusterSequence.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/FjClusterSequence.hh	(revision 11)
@@ -0,0 +1,83 @@
+//STARTHEADER
+// $Id: FjClusterSequence.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FJCLUSTERSEQUENCE_HH__
+#define __FJCLUSTERSEQUENCE_HH__
+
+
+#ifndef __BACKWARD_WARNING_V1__
+#define __BACKWARD_WARNING_V1__
+#warning This file includes at least one deprecated FastJet header from v1. \
+All fastjet components (including plugins) should now be accessed by including fastjet/...
+#endif // __BACKWARD_WARNING_V1__
+
+#include "fastjet/ClusterSequence.hh"
+
+
+/// typedef which provides backwards compatibility for 
+/// user programs based on the v1 interface
+typedef fastjet::ClusterSequence FjClusterSequence;
+
+/// typedef which provides backwards compatibility for 
+/// user programs based on the v1 interface
+typedef fastjet::Strategy        FjStrategy;
+
+
+// below follow redefinitions of all the strategy constants
+// to allow a v1 legacy user to access the strategy names
+// as before
+
+/// experimental ...
+const FjStrategy N2MinHeapTiled   = fastjet::N2MinHeapTiled;
+/// fastest from about 50..10^4
+const FjStrategy N2Tiled     = fastjet::N2Tiled;
+/// legacy
+const FjStrategy N2PoorTiled = fastjet::N2PoorTiled;
+/// fastest below 50
+const FjStrategy N2Plain     = fastjet::N2Plain;
+/// worse even than the usual N^3 algorithms
+const FjStrategy N3Dumb      = fastjet::N3Dumb;
+/// automatic selection of the best (based on N)
+const FjStrategy Best        = fastjet::Best;
+/// best of the NlnN variants -- best overall for N>10^4
+const FjStrategy NlnN        = fastjet::NlnN;
+/// legacy N ln N using 3pi coverage of cylinder
+const FjStrategy NlnN3pi     = fastjet::NlnN3pi;
+/// legacy N ln N using 4pi coverage of cylinder
+const FjStrategy NlnN4pi     = fastjet::NlnN4pi;
+/// Chan's closest pair method (in a variant with 4pi coverage),
+/// for use exclusively with the Cambridge algorithm
+const FjStrategy NlnNCam4pi   = fastjet::NlnNCam4pi;
+const FjStrategy NlnNCam2pi2R = fastjet::NlnNCam2pi2R;
+const FjStrategy NlnNCam      = fastjet::NlnNCam; // 2piMultD
+
+
+#endif //__FJCLUSTERSEQUENCE_HH__
Index: /trunk/Utilities/Fastjet/include/FjPseudoJet.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/FjPseudoJet.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/FjPseudoJet.hh	(revision 11)
@@ -0,0 +1,52 @@
+//STARTHEADER
+// $Id: FjPseudoJet.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FJPSEUDOJET_HH__
+#define __FJPSEUDOJET_HH__
+
+#ifndef __BACKWARD_WARNING_V1__
+#define __BACKWARD_WARNING_V1__
+#warning This file includes at least one deprecated FastJet header from v1. \
+All fastjet components (including plugins) should now be accessed by including fastjet/...
+#endif // __BACKWARD_WARNING_V1__
+
+
+#include "fastjet/PseudoJet.hh"
+
+/// typedef which provides backwards compatibility for 
+/// user programs based on the v1 interface
+typedef fastjet::PseudoJet FjPseudoJet;
+
+/// thought not officially "declared" in the docuementation, 
+/// this was used in the v1 fastjet_timing.cc example program,
+/// so in order to ensure that it still compiles we define it...
+const double twopi = fastjet::twopi;
+
+#endif //__FJPSEUDOJET_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ActiveAreaSpec.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ActiveAreaSpec.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ActiveAreaSpec.hh	(revision 11)
@@ -0,0 +1,45 @@
+//STARTHEADER
+// $Id: ActiveAreaSpec.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_ACTIVEAREASPEC_HH__
+#define __FASTJET_ACTIVEAREASPEC_HH__
+#include "Utilities/Fastjet/include/fastjet/GhostedAreaSpec.hh"
+
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// just provide a typedef for backwards compatibility with programs
+/// based on versions 2.0 and 2.1 of fastjet
+typedef GhostedAreaSpec ActiveAreaSpec;
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_ACTIVEAREASPEC_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/AreaDefinition.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/AreaDefinition.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/AreaDefinition.hh	(revision 11)
@@ -0,0 +1,152 @@
+//STARTHEADER
+// $Id: AreaDefinition.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2006-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_AREADEFINITION_HH__
+#define __FASTJET_AREADEFINITION_HH__
+
+#include "Utilities/Fastjet/include/fastjet/GhostedAreaSpec.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+//
+/// class for holding a "Voronoi area" specification; an area will be
+/// assigned to each particle, which is the area of the intersection
+/// of the particle's Voronoi cell with a circle of radius
+/// R*effective_Rfact.
+///
+class VoronoiAreaSpec {
+public:
+
+  /// default constructor (effective_Rfact = 1);
+  VoronoiAreaSpec() : _effective_Rfact(1.0) {};
+  
+  /// constructor that allows you to set effective_Rfact.
+  VoronoiAreaSpec(double effective_Rfact) : 
+    _effective_Rfact(effective_Rfact) {};
+
+  /// return the value of effective_Rfact
+  double effective_Rfact() const {return _effective_Rfact;}
+
+  /// return a textual description of the area definition.
+  std::string description() const;
+
+private:
+  double _effective_Rfact;
+};
+
+
+/// the different types of area that are supported
+enum AreaType {invalid_area = -1, 
+               active_area = 0, active_area_explicit_ghosts = 1,
+               one_ghost_passive_area = 10, passive_area = 11, 
+               voronoi_area=20};
+
+
+//----------------------------------------------------------------------
+/// class that holds a generic area definition
+///
+class AreaDefinition {
+public:
+  
+  /// default constructor, which provides a ghosted active area, with
+  /// sensible defaults for the ghosts.
+  AreaDefinition() {
+    _area_type  = active_area;
+    _ghost_spec = GhostedAreaSpec();
+  }
+
+  /// constructor for an area definition based on an area type and a
+  /// ghosted area specification
+  AreaDefinition(AreaType type, const GhostedAreaSpec & spec) {
+    _ghost_spec = spec;
+    _area_type   = type;
+    assert(type != voronoi_area);
+  }
+
+  /// constructor for an area definition based on an area type and a
+  /// voronoi area specification (type must be voronoi_area)
+  AreaDefinition(AreaType type, const VoronoiAreaSpec & spec) {
+    _voronoi_spec = spec;
+    _area_type   = type;
+    assert(type == voronoi_area);
+  }
+
+  /// constructor for an area definition based on an area type and 
+  /// which attempts to provide sensible defaults for everything else
+  AreaDefinition(AreaType type) {
+    _area_type   = type;
+    if (type == voronoi_area) {
+      _voronoi_spec = VoronoiAreaSpec();
+    } else {
+      _ghost_spec = GhostedAreaSpec();
+    }
+  }
+
+  /// constructor for an area definition based on an ghosted area
+  /// specification, and an option to select which ghosted area you want
+  AreaDefinition(const GhostedAreaSpec & spec, AreaType type = active_area) {
+    _ghost_spec = spec;
+    _area_type   = type;
+    assert(type != voronoi_area);
+  }
+
+  /// constructor for an area definition based on a voronoi area
+  /// specification
+  AreaDefinition(const VoronoiAreaSpec & spec) {
+    _voronoi_spec = spec;
+    _area_type    = voronoi_area;
+  }
+
+  /// return a description of the current area definition
+  std::string description() const;
+
+  /// return info about the type of area being used by this defn
+  AreaType area_type() const {return _area_type;}
+
+  /// return a reference to the active area spec
+  const GhostedAreaSpec  & ghost_spec()  const {return _ghost_spec;}
+  GhostedAreaSpec & ghost_spec()  {return _ghost_spec;}
+
+  /// return a reference to the voronoi area spec
+  const VoronoiAreaSpec & voronoi_spec() const {return _voronoi_spec;}
+  
+private:
+
+  AreaType        _area_type;
+  GhostedAreaSpec  _ghost_spec;
+  VoronoiAreaSpec _voronoi_spec;
+};
+
+FASTJET_END_NAMESPACE        // defined in fastjet/internal/base.hh
+
+
+#endif // __FASTJET_AREADEFINITION_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequence.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequence.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequence.hh	(revision 11)
@@ -0,0 +1,752 @@
+//STARTHEADER
+// $Id: ClusterSequence.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+//----------------------------------------------------------------------
+// here's where we put the main page for fastjet (as explained in the
+// Doxygen faq)
+//......................................................................
+/*! \mainpage FastJet code documentation
+ *
+ * These pages provide automatically generated documentation for the 
+ * FastJet package.
+ * 
+ * For further information and normal documentation, see the main <a
+ * href="http://www.lpthe.jussieu.fr/~salam/fastjet">FastJet</a> page.
+ */
+//----------------------------------------------------------------------
+
+#ifndef __FASTJET_CLUSTERSEQUENCE_HH__
+#define __FASTJET_CLUSTERSEQUENCE_HH__
+
+#include<vector>
+#include<map>
+#include "Utilities/Fastjet/include/fastjet/internal/DynamicNearestNeighbours.hh"
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include<memory>
+#include<cassert>
+#include<iostream>
+#include<string>
+#include<cmath> // needed to get double std::abs(double)
+#include "Utilities/Fastjet/include/fastjet/Error.hh"
+#include "Utilities/Fastjet/include/fastjet/JetDefinition.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+/// deals with clustering
+class ClusterSequence {
+
+
+ public: 
+
+  /// default constructor
+  ClusterSequence () {}
+
+  /// create a clustersequence starting from the supplied set
+  /// of pseudojets and clustering them with the long-invariant
+  /// kt algorithm (E-scheme recombination) with the supplied
+  /// value for R.
+  ///
+  /// If strategy=DumbN3 a very stupid N^3 algorithm is used for the
+  /// clustering; otherwise strategy = NlnN* uses cylinders algorithms
+  /// with some number of pi coverage. If writeout_combinations=true a
+  /// summary of the recombination sequence is written out
+  template<class L> ClusterSequence (const std::vector<L> & pseudojets, 
+		   const double & R = 1.0,
+		   const Strategy & strategy = Best,
+		   const bool & writeout_combinations = false);
+
+
+  /// create a clustersequence starting from the supplied set
+  /// of pseudojets and clustering them with jet definition specified
+  /// by jet_def (which also specifies the clustering strategy)
+  template<class L> ClusterSequence (
+			          const std::vector<L> & pseudojets,
+				  const JetDefinition & jet_def,
+				  const bool & writeout_combinations = false);
+
+
+  // NB: in the routines that follow, for extracting lists of jets, a
+  //     list structure might be more efficient, if sometimes a little
+  //     more awkward to use (at least for old fortran hands).
+
+  /// return a vector of all jets (in the sense of the inclusive
+  /// algorithm) with pt >= ptmin. Time taken should be of the order
+  /// of the number of jets returned.
+  std::vector<PseudoJet> inclusive_jets (const double & ptmin = 0.0) const;
+
+  /// return the number of jets (in the sense of the exclusive
+  /// algorithm) that would be obtained when running the algorithm
+  /// with the given dcut.
+  int n_exclusive_jets (const double & dcut) const;
+
+  /// return a vector of all jets (in the sense of the exclusive
+  /// algorithm) that would be obtained when running the algorithm
+  /// with the given dcut.
+  std::vector<PseudoJet> exclusive_jets (const double & dcut) const;
+
+  /// return a vector of all jets when the event is clustered (in the
+  /// exclusive sense) to exactly njets.
+  std::vector<PseudoJet> exclusive_jets (const int & njets) const;
+
+  /// return the dmin corresponding to the recombination that went from
+  /// n+1 to n jets (sometimes known as d_{n n+1}).
+  double exclusive_dmerge (const int & njets) const;
+
+  /// return the maximum of the dmin encountered during all recombinations 
+  /// up to the one that led to an n-jet final state; identical to
+  /// exclusive_dmerge, except in cases where the dmin do not increase
+  /// monotonically.
+  double exclusive_dmerge_max (const int & njets) const;
+
+  /// returns true iff the object is included in the jet. 
+  ///
+  /// NB: this is only sensible if the object is already registered
+  /// within the cluster sequence, so you cannot use it with an input
+  /// particle to the CS (since the particle won't have the history
+  /// index set properly).
+  ///
+  /// For nice clustering structures it should run in O(ln(N)) time
+  /// but in worst cases (certain cone plugins) it can take O(n) time,
+  /// where n is the number of particles in the jet.
+  bool object_in_jet(const PseudoJet & object, const PseudoJet & jet) const;
+
+  /// if the jet has parents in the clustering, it returns true
+  /// and sets parent1 and parent2 equal to them.
+  ///
+  /// if it has no parents it returns false and sets parent1 and
+  /// parent2 to zero
+  bool has_parents(const PseudoJet & jet, PseudoJet & parent1, 
+               PseudoJet & parent2) const;
+
+  /// if the jet has a child then return true and give the child jet
+  /// otherwise return false and set the child to zero
+  bool has_child(const PseudoJet & jet, PseudoJet & child) const;
+
+  /// Version of has_child that sets a pointer to the child if the child
+  /// exists;
+  bool has_child(const PseudoJet & jet, const PseudoJet * & childp) const;
+
+  /// if this jet has a child (and so a partner) return true
+  /// and give the partner, otherwise return false and set the
+  /// partner to zero
+  bool has_partner(const PseudoJet & jet, PseudoJet & partner) const;
+
+  /// return a vector of the particles that make up jet
+  std::vector<PseudoJet> constituents (const PseudoJet & jet) const;
+
+
+  /// output the supplied vector of jets in a format that can be read
+  /// by an appropriate root script; the format is:
+  /// jet-n jet-px jet-py jet-pz jet-E 
+  ///   particle-n particle-rap particle-phi particle-pt
+  ///   particle-n particle-rap particle-phi particle-pt
+  ///   ...
+  /// #END
+  /// ... [i.e. above repeated]
+  void print_jets_for_root(const std::vector<PseudoJet> & jets, 
+                           std::ostream & ostr = std::cout) const;
+
+// Not yet. Perhaps in a future release.
+//   /// print out all inclusive jets with pt > ptmin
+//   virtual void print_jets (const double & ptmin=0.0) const;
+
+  /// add on to subjet_vector the subjets of jet (for internal use mainly)
+  void add_constituents (const PseudoJet & jet, 
+			 std::vector<PseudoJet> & subjet_vector) const;
+
+  /// return the enum value of the strategy used to cluster the event
+  inline Strategy strategy_used () const {return _strategy;}
+  std::string strategy_string () const;
+
+  /// return a reference to the jet definition
+  const JetDefinition & jet_def() const {return _jet_def;}
+
+  /// returns the scale associated with a jet as required for this
+  /// clustering algorithm (kt^2 for the kt-algorithm, 1 for the 
+  /// Cambridge algorithm). [May become virtual at some point]
+  double jet_scale_for_algorithm(const PseudoJet & jet) const;
+
+  //----- next follow functions designed specifically for plugins, which
+  //      may only be called when plugin_activated() returns true
+
+  /// record the fact that there has been a recombination between
+  /// jets()[jet_i] and jets()[jet_k], with the specified dij, and
+  /// return the index (newjet_k) allocated to the new jet, whose
+  /// momentum is assumed to be the 4-vector sum of that of jet_i and
+  /// jet_j
+  void plugin_record_ij_recombination(int jet_i, int jet_j, double dij, 
+				      int & newjet_k) {
+    assert(plugin_activated());
+    _do_ij_recombination_step(jet_i, jet_j, dij, newjet_k);
+  }
+
+  /// as for the simpler variant of plugin_record_ij_recombination,
+  /// except that the new jet is attributed the momentum and
+  /// user_index of newjet
+  void plugin_record_ij_recombination(int jet_i, int jet_j, double dij, 
+				      const PseudoJet & newjet, 
+				      int & newjet_k);
+
+  /// record the fact that there has been a recombination between
+  /// jets()[jet_i] and the beam, with the specified diB; when looking
+  /// for inclusive jets, any iB recombination will returned to the user 
+  /// as a jet.
+  void plugin_record_iB_recombination(int jet_i, double diB) {
+    assert(plugin_activated());
+    _do_iB_recombination_step(jet_i, diB);
+  }
+
+  /// a class intended to serve as a base in case a plugin needs to
+  /// associate extra information with a ClusterSequence (see
+  /// SISConePlugin.* for an example).
+  class Extras {
+  public:
+    virtual ~Extras() {}
+    virtual std::string description() const {return "This is a dummy extras class that contains no extra information! Derive from it if you want to use it to provide extra information from a plugin jet finder";}
+  };
+
+  /// the plugin can associated some extra information with the
+  /// ClusterSequence object by calling this function
+  inline void plugin_associate_extras(std::auto_ptr<Extras> extras_in) {
+    _extras = extras_in;
+  }
+
+  /// returns true when the plugin is allowed to run the show.
+  inline bool plugin_activated() const {return _plugin_activated;}
+
+  /// returns a pointer to the extras object (may be null)
+  const Extras * extras() const {return _extras.get();}
+
+public:
+  /// set the default (static) jet finder across all current and future
+  /// ClusterSequence objects -- deprecated and obsolescent (i.e. may be
+  /// suppressed in a future release).
+  static void set_jet_algorithm (JetAlgorithm jet_algorithm) {_default_jet_algorithm = jet_algorithm;}
+  /// same as above for backward compatibility
+  static void set_jet_finder (JetAlgorithm jet_algorithm)    {_default_jet_algorithm = jet_algorithm;}
+
+
+  /// a single element in the clustering history (see vector _history
+  /// below).
+  struct history_element{
+    int parent1; /// index in _history where first parent of this jet
+                 /// was created (InexistentParent if this jet is an
+                 /// original particle)
+
+    int parent2; /// index in _history where second parent of this jet
+                 /// was created (InexistentParent if this jet is an
+                 /// original particle); BeamJet if this history entry
+                 /// just labels the fact that the jet has recombined
+                 /// with the beam)
+
+    int child;   /// index in _history where the current jet is
+		 /// recombined with another jet to form its child. It
+		 /// is Invalid if this jet does not further
+		 /// recombine.
+
+    int jetp_index; /// index in the _jets vector where we will find the
+                 /// PseudoJet object corresponding to this jet
+                 /// (i.e. the jet created at this entry of the
+                 /// history). NB: if this element of the history
+                 /// corresponds to a beam recombination, then
+                 /// jetp_index=Invalid.
+
+    double dij;  /// the distance corresponding to the recombination
+		 /// at this stage of the clustering.
+
+    double max_dij_so_far; /// the largest recombination distance seen
+			   /// so far in the clustering history.
+  };
+
+  enum JetType {Invalid=-3, InexistentParent = -2, BeamJet = -1};
+
+  /// allow the user to access the jets in this raw manner (needed
+  /// because we don't seem to be able to access protected elements of
+  /// the class for an object that is not "this" (at least in case where
+  /// "this" is of a slightly different kind from the object, both
+  /// derived from ClusterSequence).
+  const std::vector<PseudoJet> & jets()    const;
+
+  /// allow the user to access the history in this raw manner (see
+  /// above for motivation).
+  const std::vector<history_element> & history() const;
+
+  /// returns the number of particles that were provided to the
+  /// clustering algorithm (helps the user find their way around the
+  /// history and jets objects if they weren't paying attention
+  /// beforehand).
+  unsigned int n_particles() const;
+
+  /// returns a vector of size n_particles() which indicates, for 
+  /// each of the initial particles (in the order in which they were
+  /// supplied), which of the supplied jets it belongs to; if it does
+  /// not belong to any of the supplied jets, the index is set to -1;
+  std::vector<int> particle_jet_indices(const std::vector<PseudoJet> &) const;
+
+  /// routine that returns an order in which to read the history
+  /// such that clusterings that lead to identical jet compositions
+  /// but different histories (because of degeneracies in the
+  /// clustering order) will have matching constituents for each
+  /// matching entry in the unique_history_order.
+  ///
+  /// The order has the property that an entry's parents will always
+  /// appear prior to that entry itself. 
+  ///
+  /// Roughly speaking the order is such that we first provide all
+  /// steps that lead to the final jet containing particle 1; then we
+  /// have the steps that lead to reconstruction of the jet containing
+  /// the next-lowest-numbered unclustered particle, etc...
+  /// [see GPS CCN28-12 for more info -- of course a full explanation
+  /// here would be better...]
+  std::vector<int> unique_history_order() const;
+
+  /// return the set of particles that have not been clustered. For 
+  /// kt and cam/aachen algorithms this should always be null, but for
+  /// cone type algorithms it can be non-null;
+  std::vector<PseudoJet> unclustered_particles() const;
+
+  /// transfer the sequence contained in other_seq into our own;
+  /// any plugin "extras" contained in the from_seq will be lost
+  /// from there.
+  void transfer_from_sequence(ClusterSequence & from_seq);
+
+protected:
+  static JetAlgorithm _default_jet_algorithm;
+  JetDefinition _jet_def;
+
+  /// returns true if the jet has a history index contained within
+  /// the range of this CS
+  bool _potentially_valid(const PseudoJet & jet) const {
+    return jet.cluster_hist_index() >= 0 
+      && jet.cluster_hist_index() < int(_history.size());
+  }
+
+  /// transfer the vector<L> of input jets into our own vector<PseudoJet>
+  /// _jets (with some reserved space for future growth).
+  template<class L> void _transfer_input_jets(
+                                     const std::vector<L> & pseudojets);
+
+  /// This is the routine that will do all the initialisation and
+  /// then run the clustering (may be called by various constructors).
+  /// It assumes _jets contains the momenta to be clustered.
+  void _initialise_and_run (const JetDefinition & jet_def,
+			    const bool & writeout_combinations);
+
+  /// This is an alternative routine for initialising and running the
+  /// clustering, provided for legacy purposes. The jet finder is that
+  /// specified in the static member _default_jet_algorithm.
+  void _initialise_and_run (const double & R,
+			    const Strategy & strategy,
+			    const bool & writeout_combinations);
+
+  /// fills in the various member variables with "decanted" options from
+  /// the jet_definition and writeout_combinations variables
+  void _decant_options(const JetDefinition & jet_def,
+                       const bool & writeout_combinations);
+
+  /// fill out the history (and jet cross refs) related to the initial
+  /// set of jets (assumed already to have been "transferred"),
+  /// without any clustering
+  void _fill_initial_history();
+
+  /// carry out the recombination between the jets numbered jet_i and
+  /// jet_j, at distance scale dij; return the index newjet_k of the
+  /// result of the recombination of i and j.
+  void _do_ij_recombination_step(const int & jet_i, const int & jet_j, 
+				 const double & dij, int & newjet_k);
+
+  /// carry out an recombination step in which _jets[jet_i] merges with
+  /// the beam, 
+  void _do_iB_recombination_step(const int & jet_i, const double & diB);
+
+
+  /// This contains the physical PseudoJets; for each PseudoJet one
+  /// can find the corresponding position in the _history by looking
+  /// at _jets[i].cluster_hist_index().
+  std::vector<PseudoJet> _jets;
+
+
+  /// this vector will contain the branching history; for each stage,
+  /// _history[i].jetp_index indicates where to look in the _jets
+  /// vector to get the physical PseudoJet.
+  std::vector<history_element> _history;
+
+  bool _writeout_combinations;
+  int  _initial_n;
+  double _Rparam, _R2, _invR2;
+  Strategy    _strategy;
+  JetAlgorithm  _jet_algorithm;
+
+ private:
+
+  bool _plugin_activated;
+  std::auto_ptr<Extras> _extras; // things the plugin might want to add
+
+  void _really_dumb_cluster ();
+  void _delaunay_cluster ();
+  void _simple_N2_cluster ();
+  void _tiled_N2_cluster ();
+  void _faster_tiled_N2_cluster ();
+
+  //
+  void _minheap_faster_tiled_N2_cluster();
+
+  // things needed specifically for Cambridge with Chan's 2D closest
+  // pairs method
+  void _CP2DChan_cluster();
+  void _CP2DChan_cluster_2pi2R ();
+  void _CP2DChan_cluster_2piMultD ();
+  void _CP2DChan_limited_cluster(double D);
+  void _do_Cambridge_inclusive_jets();
+
+  void _add_step_to_history(const int & step_number, const int & parent1, 
+			       const int & parent2, const int & jetp_index,
+			       const double & dij);
+
+  /// internal routine associated with the construction of the unique
+  /// history order (following children in the tree)
+  void _extract_tree_children(int pos, std::valarray<bool> &, 
+		const std::valarray<int> &, std::vector<int> &) const;
+
+  /// internal routine associated with the construction of the unique
+  /// history order (following parents in the tree)
+  void _extract_tree_parents (int pos, std::valarray<bool> &, 
+                const std::valarray<int> &,  std::vector<int> &) const;
+
+
+  // these will be useful shorthands in the Voronoi-based code
+  typedef std::pair<int,int> TwoVertices;
+  typedef std::pair<double,TwoVertices> DijEntry;
+  typedef std::multimap<double,TwoVertices> DistMap;
+
+  /// currently used only in the Voronoi based code
+  void _add_ktdistance_to_map(const int & ii, 
+			      DistMap & DijMap,
+  			      const DynamicNearestNeighbours * DNN);
+
+  /// for making sure the user knows what it is they're running...
+  void _print_banner();
+  /// will be set by default to be true for the first run
+  static bool _first_time;
+
+  /// record the number of warnings provided about the exclusive
+  /// algorithm -- so that we don't print it out more than a few
+  /// times.
+  static int _n_exclusive_warnings;
+
+  //----------------------------------------------------------------------
+  /// the fundamental structure which contains the minimal info about
+  /// a jet, as needed for our plain N^2 algorithm -- the idea is to
+  /// put all info that will be accessed N^2 times into an array of
+  /// BriefJets...
+  struct BriefJet {
+    double     eta, phi, kt2, NN_dist;
+    BriefJet * NN;
+    int        _jets_index;
+  };
+  /// structure analogous to BriefJet, but with the extra information
+  /// needed for dealing with tiles
+  class TiledJet {
+  public:
+    double     eta, phi, kt2, NN_dist;
+    TiledJet * NN, *previous, * next; 
+    int        _jets_index, tile_index, diJ_posn;
+    // routines that are useful in the minheap version of tiled
+    // clustering ("misuse" the otherwise unused diJ_posn, so as
+    // to indicate whether jets need to have their minheap entries
+    // updated).
+    inline void label_minheap_update_needed() {diJ_posn = 1;}
+    inline void label_minheap_update_done()   {diJ_posn = 0;}
+    inline bool minheap_update_needed() const {return diJ_posn==1;}
+  };
+
+  //-- some of the functions that follow are templates and will work
+  //as well for briefjet and tiled jets
+
+  /// set the kinematic and labelling info for jeta so that it corresponds
+  /// to _jets[_jets_index]
+  template <class J> void _bj_set_jetinfo( J * const jet, 
+						 const int _jets_index) const;
+
+  /// "remove" this jet, which implies updating links of neighbours and
+  /// perhaps modifying the tile structure
+  void _bj_remove_from_tiles( TiledJet * const jet) const;
+
+  /// return the distance between two BriefJet objects
+  template <class J> double _bj_dist(const J * const jeta, 
+			const J * const jetb) const;
+
+  // return the diJ (multiplied by _R2) for this jet assuming its NN
+  // info is correct
+  template <class J> double _bj_diJ(const J * const jeta) const;
+
+  /// for testing purposes only: if in the range head--tail-1 there is a
+  /// a jet which corresponds to hist_index in the history, then
+  /// return a pointer to that jet; otherwise return tail.
+  template <class J> inline J * _bj_of_hindex(
+                          const int hist_index, 
+			  J * const head, J * const tail) 
+    const {
+    J * res;
+    for(res = head; res<tail; res++) {
+      if (_jets[res->_jets_index].cluster_hist_index() == hist_index) {break;}
+    }
+    return res;
+  }
+
+
+  //-- remaining functions are different in various cases, so we
+  //   will use templates but are not sure if they're useful...
+
+  /// updates (only towards smaller distances) the NN for jeta without checking
+  /// whether in the process jeta itself might be a new NN of one of
+  /// the jets being scanned -- span the range head to tail-1 with
+  /// assumption that jeta is not contained in that range
+  template <class J> void _bj_set_NN_nocross(J * const jeta, 
+            J * const head, const J * const tail) const;
+
+  /// reset the NN for jeta and DO check whether in the process jeta
+  /// itself might be a new NN of one of the jets being scanned --
+  /// span the range head to tail-1 with assumption that jeta is not
+  /// contained in that range
+  template <class J> void _bj_set_NN_crosscheck(J * const jeta, 
+            J * const head, const J * const tail) const;
+  
+
+
+  /// number of neighbours that a tile will have (rectangular geometry
+  /// gives 9 neighbours).
+  static const int n_tile_neighbours = 9;
+  //----------------------------------------------------------------------
+  /// The fundamental structures to be used for the tiled N^2 algorithm
+  /// (see CCN27-44 for some discussion of pattern of tiling)
+  struct Tile {
+    /// pointers to neighbouring tiles, including self
+    Tile *   begin_tiles[n_tile_neighbours]; 
+    /// neighbouring tiles, excluding self
+    Tile **  surrounding_tiles; 
+    /// half of neighbouring tiles, no self
+    Tile **  RH_tiles;  
+    /// just beyond end of tiles
+    Tile **  end_tiles; 
+    /// start of list of BriefJets contained in this tile
+    TiledJet * head;    
+    /// sometimes useful to be able to tag a tile
+    bool     tagged;    
+  };
+  std::vector<Tile> _tiles;
+  double _tiles_eta_min, _tiles_eta_max;
+  double _tile_size_eta, _tile_size_phi;
+  int    _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
+
+  // reasonably robust return of tile index given ieta and iphi, in particular
+  // it works even if iphi is negative
+  inline int _tile_index (int ieta, int iphi) const {
+    // note that (-1)%n = -1 so that we have to add _n_tiles_phi
+    // before performing modulo operation
+    return (ieta-_tiles_ieta_min)*_n_tiles_phi
+                  + (iphi+_n_tiles_phi) % _n_tiles_phi;
+  }
+
+  // routines for tiled case, including some overloads of the plain
+  // BriefJet cases
+  int  _tile_index(const double & eta, const double & phi) const;
+  void _tj_set_jetinfo ( TiledJet * const jet, const int _jets_index);
+  void  _bj_remove_from_tiles(TiledJet * const jet);
+  void _initialise_tiles();
+  void _print_tiles(TiledJet * briefjets ) const;
+  void _add_neighbours_to_tile_union(const int tile_index, 
+		 std::vector<int> & tile_union, int & n_near_tiles) const;
+  void _add_untagged_neighbours_to_tile_union(const int tile_index, 
+		 std::vector<int> & tile_union, int & n_near_tiles);
+
+
+};
+
+
+
+//**********************************************************************
+//**************    START   OF   INLINE   MATERIAL    ******************
+//**********************************************************************
+
+
+//----------------------------------------------------------------------
+// Transfer the initial jets into our internal structure
+template<class L> void ClusterSequence::_transfer_input_jets(
+                                       const std::vector<L> & pseudojets) {
+
+  // this will ensure that we can point to jets without difficulties
+  // arising.
+  _jets.reserve(pseudojets.size()*2);
+
+  // insert initial jets this way so that any type L that can be
+  // converted to a pseudojet will work fine (basically PseudoJet
+  // and any type that has [] subscript access to the momentum
+  // components, such as CLHEP HepLorentzVector).
+  for (unsigned int i = 0; i < pseudojets.size(); i++) {
+    _jets.push_back(pseudojets[i]);}
+  
+}
+
+//----------------------------------------------------------------------
+// initialise from some generic type... Has to be made available
+// here in order for it the template aspect of it to work...
+template<class L> ClusterSequence::ClusterSequence (
+			          const std::vector<L> & pseudojets,
+				  const double & R,
+				  const Strategy & strategy,
+				  const bool & writeout_combinations) {
+
+  // transfer the initial jets (type L) into our own array
+  _transfer_input_jets(pseudojets);
+
+  // run the clustering
+  _initialise_and_run(R,strategy,writeout_combinations);
+}
+
+
+//----------------------------------------------------------------------
+/// constructor of a jet-clustering sequence from a vector of
+/// four-momenta, with the jet definition specified by jet_def
+template<class L> ClusterSequence::ClusterSequence (
+			          const std::vector<L> & pseudojets,
+				  const JetDefinition & jet_def,
+				  const bool & writeout_combinations) {
+
+  // transfer the initial jets (type L) into our own array
+  _transfer_input_jets(pseudojets);
+
+  // run the clustering
+  _initialise_and_run(jet_def,writeout_combinations);
+}
+
+
+inline const std::vector<PseudoJet> & ClusterSequence::jets () const {
+  return _jets;
+}
+
+inline const std::vector<ClusterSequence::history_element> & ClusterSequence::history () const {
+  return _history;
+}
+
+inline unsigned int ClusterSequence::n_particles() const {return _initial_n;}
+
+
+
+//----------------------------------------------------------------------
+template <class J> inline void ClusterSequence::_bj_set_jetinfo(
+                            J * const jetA, const int _jets_index) const {
+    jetA->eta  = _jets[_jets_index].rap();
+    jetA->phi  = _jets[_jets_index].phi_02pi();
+    jetA->kt2  = jet_scale_for_algorithm(_jets[_jets_index]);
+    jetA->_jets_index = _jets_index;
+    // initialise NN info as well
+    jetA->NN_dist = _R2;
+    jetA->NN      = NULL;
+}
+
+
+
+
+//----------------------------------------------------------------------
+template <class J> inline double ClusterSequence::_bj_dist(
+                const J * const jetA, const J * const jetB) const {
+  double dphi = std::abs(jetA->phi - jetB->phi);
+  double deta = (jetA->eta - jetB->eta);
+  if (dphi > pi) {dphi = twopi - dphi;}
+  return dphi*dphi + deta*deta;
+}
+
+//----------------------------------------------------------------------
+template <class J> inline double ClusterSequence::_bj_diJ(const J * const jet) const {
+  double kt2 = jet->kt2;
+  if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
+  return jet->NN_dist * kt2;
+}
+
+
+//----------------------------------------------------------------------
+// set the NN for jet without checking whether in the process you might
+// have discovered a new nearest neighbour for another jet
+template <class J> inline void ClusterSequence::_bj_set_NN_nocross(
+                 J * const jet, J * const head, const J * const tail) const {
+  double NN_dist = _R2;
+  J * NN  = NULL;
+  if (head < jet) {
+    for (J * jetB = head; jetB != jet; jetB++) {
+      double dist = _bj_dist(jet,jetB);
+      if (dist < NN_dist) {
+	NN_dist = dist;
+	NN = jetB;
+      }
+    }
+  }
+  if (tail > jet) {
+    for (J * jetB = jet+1; jetB != tail; jetB++) {
+      double dist = _bj_dist(jet,jetB);
+      if (dist < NN_dist) {
+	NN_dist = dist;
+	NN = jetB;
+      }
+    }
+  }
+  jet->NN = NN;
+  jet->NN_dist = NN_dist;
+}
+
+
+//----------------------------------------------------------------------
+template <class J> inline void ClusterSequence::_bj_set_NN_crosscheck(J * const jet, 
+		    J * const head, const J * const tail) const {
+  double NN_dist = _R2;
+  J * NN  = NULL;
+  for (J * jetB = head; jetB != tail; jetB++) {
+    double dist = _bj_dist(jet,jetB);
+    if (dist < NN_dist) {
+      NN_dist = dist;
+      NN = jetB;
+    }
+    if (dist < jetB->NN_dist) {
+      jetB->NN_dist = dist;
+      jetB->NN = jet;
+    }
+  }
+  jet->NN = NN;
+  jet->NN_dist = NN_dist;
+}
+
+
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCE_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequence1GhostPassiveArea.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequence1GhostPassiveArea.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequence1GhostPassiveArea.hh	(revision 11)
@@ -0,0 +1,101 @@
+//STARTHEADER
+// $Id: ClusterSequence1GhostPassiveArea.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCE1GHOSTPASSIVEAREA_HH__
+#define __FASTJET_CLUSTERSEQUENCE1GHOSTPASSIVEAREA_HH__
+
+
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceActiveArea.hh"
+#include<iostream>
+#include<vector>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//using namespace std;
+
+/// Class that behaves essentially like ClusterSequence except
+/// that it also provides access to the area of a jet (which
+/// will be a random quantity... Figure out what to do about seeds 
+/// later...)
+class ClusterSequence1GhostPassiveArea : public ClusterSequenceActiveArea {
+public:
+
+  ClusterSequence1GhostPassiveArea() {}
+
+  /// constructor based on JetDefinition and 1GhostPassiveAreaSpec
+  template<class L> ClusterSequence1GhostPassiveArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const GhostedAreaSpec & area_spec,
+	  const bool & writeout_combinations = false) ;
+
+  /// return an estimate for the number of empty jets -- one uses the
+  /// AreaBase one rather than the ActiveArea one (which for which we
+  /// do not have the information).
+  virtual double n_empty_jets(const RangeDefinition & range) const {
+    return ClusterSequenceAreaBase::n_empty_jets(range);
+  }
+
+protected:
+  /// does the initialisation and running specific to the passive
+  /// areas class
+  void _initialise_and_run_1GPA (const JetDefinition & jet_def,
+                               const GhostedAreaSpec & area_spec,
+                               const bool & writeout_combinations = false);
+
+private:
+
+  void _run_1GPA(const GhostedAreaSpec & area_spec);
+};
+
+
+
+
+template<class L> ClusterSequence1GhostPassiveArea::ClusterSequence1GhostPassiveArea 
+(const std::vector<L> & pseudojets, 
+ const JetDefinition & jet_def,
+ const GhostedAreaSpec & area_spec,
+ const bool & writeout_combinations) {
+
+  // transfer the initial jets (type L) into our own array
+  _transfer_input_jets(pseudojets);
+
+  // run the clustering for passive areas
+  _initialise_and_run_1GPA(jet_def, area_spec, writeout_combinations);
+
+}
+
+
+  
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCE1GHOSTPASSIVEAREA_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceActiveArea.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceActiveArea.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceActiveArea.hh	(revision 11)
@@ -0,0 +1,221 @@
+//STARTHEADER
+// $Id: ClusterSequenceActiveArea.hh,v 1.1 2008-11-06 14:32:07 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEACTIVEAREA_HH__
+#define __FASTJET_CLUSTERSEQUENCEACTIVEAREA_HH__
+
+
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
+#include<iostream>
+#include<vector>
+
+//------------ backwards compatibility with version 2.1 -------------
+// for backwards compatibility make ActiveAreaSpec name available
+#include "Utilities/Fastjet/include/fastjet/ActiveAreaSpec.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceWithArea.hh"
+//--------------------------------------------------------------------
+
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//using namespace std;
+
+/// Class that behaves essentially like ClusterSequence except
+/// that it also provides access to the area of a jet (which
+/// will be a random quantity... Figure out what to do about seeds 
+/// later...)
+class ClusterSequenceActiveArea : public ClusterSequenceAreaBase {
+public:
+
+  /// default constructor
+  ClusterSequenceActiveArea() {}
+
+  /// constructor based on JetDefinition and GhostedAreaSpec
+  template<class L> ClusterSequenceActiveArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const GhostedAreaSpec & area_spec,
+	  const bool & writeout_combinations = false) ;
+
+  virtual double area (const PseudoJet & jet) const {
+                             return _average_area[jet.cluster_hist_index()];};
+  virtual double area_error (const PseudoJet & jet) const {
+                             return _average_area2[jet.cluster_hist_index()];};
+
+  virtual PseudoJet area_4vector (const PseudoJet & jet) const {
+                    return _average_area_4vector[jet.cluster_hist_index()];};
+
+  /// enum providing a variety of tentative strategies for estimating
+  /// the background (e.g. non-jet) activity in a highly populated event; the
+  /// one that has been most extensively tested is median.
+  enum mean_pt_strategies{median=0, non_ghost_median, pttot_over_areatot, 
+			  pttot_over_areatot_cut, mean_ratio_cut, play,
+			  median_4vector};
+
+  /// return the transverse momentum per unit area according to one
+  /// of the above strategies; for some strategies (those with "cut"
+  /// in their name) the parameter "range" allows one to exclude a
+  /// subset of the jets for the background estimation, those that
+  /// have pt/area > median(pt/area)*range.
+  ///
+  /// NB: This call is OBSOLETE; use media_pt_per_unit_area from the
+  //      ClusterSequenceAreaBase class instead
+  double pt_per_unit_area(mean_pt_strategies strat=median, 
+                          double range=2.0 ) const;
+
+  // following code removed -- now dealt with by AreaBase class (and
+  // this definition here conflicts with it).
+//   /// fits a form pt_per_unit_area(y) = a + b*y^2 in the range
+//   /// abs(y)<raprange (for negative raprange, it defaults to
+//   /// _safe_rap_for_area).
+//   void parabolic_pt_per_unit_area(double & a,double & b, double raprange=-1.0,
+// 				  double exclude_above=-1.0, 
+// 				  bool use_area_4vector=false ) const;
+// 
+  /// rewrite the empty area from the parent class, so as to use
+  /// all info at our disposal
+  /// return the total area, in the given y-phi range, that consists of ghost
+  /// jets or unclustered ghosts
+  virtual double empty_area(const RangeDefinition & range) const;
+
+  /// return the true number of empty jets (replaces
+  /// ClusterSequenceAreaBase::n_empty_jets(...))
+  virtual double n_empty_jets(const RangeDefinition & range) const;
+
+protected:
+  void _resize_and_zero_AA ();
+  void _initialise_AA(const JetDefinition & jet_def,
+                      const GhostedAreaSpec & area_spec,
+                      const bool & writeout_combinations,
+                      bool & continue_running);
+
+  void _run_AA(const GhostedAreaSpec & area_spec);
+
+  void _postprocess_AA(const GhostedAreaSpec & area_spec);
+
+  /// does the initialisation and running specific to the active
+  /// areas class
+  void _initialise_and_run_AA (const JetDefinition & jet_def,
+                               const GhostedAreaSpec & area_spec,
+                               const bool & writeout_combinations = false);
+
+  /// transfer the history (and jet-momenta) from clust_seq to our
+  /// own internal structure while removing ghosts
+  void _transfer_ghost_free_history(
+           const ClusterSequenceActiveAreaExplicitGhosts & clust_seq);
+
+
+  /// transfer areas from the ClusterSequenceActiveAreaExplicitGhosts
+  /// object into our internal area bookkeeping...
+  void _transfer_areas(const std::vector<int> & unique_hist_order, 
+                       const ClusterSequenceActiveAreaExplicitGhosts & );
+
+  /// child classes benefit from having these at their disposal
+  std::valarray<double> _average_area, _average_area2;
+  std::valarray<PseudoJet> _average_area_4vector;
+
+  /// returns true if there are any particles whose transverse momentum
+  /// if so low that there's a risk of the ghosts having modified the
+  /// clustering sequence
+  bool has_dangerous_particles() const {return _has_dangerous_particles;}
+
+private:
+
+
+  double           _non_jet_area, _non_jet_area2, _non_jet_number;
+
+  double _maxrap_for_area; // max rap where we put ghosts
+  double _safe_rap_for_area; // max rap where we trust jet areas
+
+  bool   _has_dangerous_particles; 
+
+
+  /// routine for extracting the tree in an order that will be independent
+  /// of any degeneracies in the recombination sequence that don't
+  /// affect the composition of the final jets
+  void _extract_tree(std::vector<int> &) const;
+  /// do the part of the extraction associated with pos, working
+  /// through its children and their parents
+  void _extract_tree_children(int pos, std::valarray<bool> &, const std::valarray<int> &, std::vector<int> &) const;
+  /// do the part of the extraction associated with the parents of pos.
+  void _extract_tree_parents (int pos, std::valarray<bool> &, const std::valarray<int> &,  std::vector<int> &) const;
+
+  /// check if two jets have the same momentum to within the
+  /// tolerance (and if pt's are not the same we're forgiving and
+  /// look to see if the energy is the same)
+  void _throw_unless_jets_have_same_perp_or_E(const PseudoJet & jet, 
+                                              const PseudoJet & refjet, 
+                                              double tolerance,
+             const ClusterSequenceActiveAreaExplicitGhosts & jets_ghosted_seq
+                                              ) const;
+
+  /// since we are playing nasty games with seeds, we should warn
+  /// the user a few times
+  //static int _n_seed_warnings;
+  //const static int _max_seed_warnings = 10;
+
+  // record the number of repeats
+  int _area_spec_repeat;
+
+  /// a class for our internal storage of ghost jets
+  class GhostJet : public PseudoJet {
+  public:
+    GhostJet(const PseudoJet & j, double a) : PseudoJet(j), area(a){}
+    double area;
+  };
+
+  std::vector<GhostJet> _ghost_jets;
+  std::vector<GhostJet> _unclustered_ghosts;
+};
+
+
+
+
+template<class L> ClusterSequenceActiveArea::ClusterSequenceActiveArea 
+(const std::vector<L> & pseudojets, 
+ const JetDefinition & jet_def,
+ const GhostedAreaSpec & area_spec,
+ const bool & writeout_combinations) {
+
+  // transfer the initial jets (type L) into our own array
+  _transfer_input_jets(pseudojets);
+
+  // run the clustering for active areas
+  _initialise_and_run_AA(jet_def, area_spec, writeout_combinations);
+
+}
+
+
+  
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEACTIVEAREA_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh	(revision 11)
@@ -0,0 +1,232 @@
+//STARTHEADER
+// $Id: ClusterSequenceActiveAreaExplicitGhosts.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEACTIVEAREAEXPLICITGHOSTS_HH_
+#define __FASTJET_CLUSTERSEQUENCEACTIVEAREAEXPLICITGHOSTS_HH_ 
+
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh"
+#include "Utilities/Fastjet/include/fastjet/GhostedAreaSpec.hh"
+#include "Utilities/Fastjet/include/fastjet/internal/LimitedWarning.hh"
+#include<iostream>
+#include<vector>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//======================================================================
+/// Class that behaves essentially like ClusterSequence except
+/// that it also provides access to the area of a jet (which
+/// will be a random quantity... Figure out what to do about seeds 
+/// later...)
+class ClusterSequenceActiveAreaExplicitGhosts : 
+  public ClusterSequenceAreaBase {
+public:
+  /// constructor using a GhostedAreaSpec to specify how the area is
+  /// to be measured
+  template<class L> ClusterSequenceActiveAreaExplicitGhosts
+         (const std::vector<L> & pseudojets, 
+          const JetDefinition & jet_def,
+	  const GhostedAreaSpec & area_spec,
+	  const bool & writeout_combinations = false) 
+	   : ClusterSequenceAreaBase() {
+           std::vector<L> * ghosts = NULL;
+	   _initialise(pseudojets,jet_def,&area_spec,ghosts,0.0,
+                       writeout_combinations); }
+
+  template<class L> ClusterSequenceActiveAreaExplicitGhosts
+         (const std::vector<L> & pseudojets, 
+          const JetDefinition & jet_def,
+          const std::vector<L> & ghosts,
+          double ghost_area,
+	  const bool & writeout_combinations = false) 
+	   : ClusterSequenceAreaBase() {
+           const GhostedAreaSpec * area_spec = NULL;
+	   _initialise(pseudojets,jet_def,area_spec,&ghosts,ghost_area,
+                       writeout_combinations); }
+
+
+  /// does the actual work of initialisation
+  template<class L> void _initialise
+         (const std::vector<L> & pseudojets, 
+          const JetDefinition & jet_def,
+	  const GhostedAreaSpec * area_spec,
+	  const std::vector<L> * ghosts,
+	  double                 ghost_area,
+	  const bool & writeout_combinations); 
+
+  //vector<PseudoJet> constituents (const PseudoJet & jet) const;
+
+  /// returns the number of hard particles (i.e. those supplied by the user).
+  unsigned int n_hard_particles() const;
+
+  /// returns the area of a jet
+  virtual double area (const PseudoJet & jet) const;
+
+  /// returns a four vector corresponding to the sum (E-scheme) of the
+  /// ghost four-vectors composing the jet area, normalised such that
+  /// for a small contiguous area the p_t of the extended_area jet is
+  /// equal to area of the jet.
+  virtual PseudoJet area_4vector (const PseudoJet & jet) const;
+
+  /// true if a jet is made exclusively of ghosts
+  virtual bool is_pure_ghost(const PseudoJet & jet) const;
+
+  /// true if the entry in the history index corresponds to a
+  /// ghost; if hist_ix does not correspond to an actual particle
+  /// (i.e. hist_ix < 0), then the result is false.
+  bool is_pure_ghost(int history_index) const;
+
+  /// return the total area, up to |y|<maxrap, that consists of
+  /// unclustered ghosts
+  virtual double empty_area(const RangeDefinition & range) const;
+
+  /// returns the total area under study
+  double total_area () const;
+  
+  /// returns the largest squared transverse momentum among
+  /// all ghosts
+  double max_ghost_perp2() const {return _max_ghost_perp2;}
+
+  /// returns true if there are any particles whose transverse momentum
+  /// if so low that there's a risk of the ghosts having modified the
+  /// clustering sequence
+  bool has_dangerous_particles() const {return _has_dangerous_particles;}
+
+private:
+
+  int    _n_ghosts;
+  double _ghost_area;
+  std::vector<bool> _is_pure_ghost;
+  std::vector<double> _areas;
+  std::vector<PseudoJet> _area_4vectors;
+  
+  // things related to checks for dangerous particles
+  double _max_ghost_perp2;
+  bool   _has_dangerous_particles; 
+  static LimitedWarning _warnings;
+
+  //static int _n_warn_dangerous_particles;
+  //static const int _max_warn_dangerous_particles = 5;
+
+  
+  unsigned int _initial_hard_n;
+
+  /// adds the "ghost" momenta, which will be used to estimate
+  /// the jet area
+  void _add_ghosts(const GhostedAreaSpec & area_spec); 
+
+  /// another way of adding ghosts
+  template<class L> void _add_ghosts (
+	  const std::vector<L> & ghosts,
+	  double                 ghost_area);
+
+  /// routine to be called after the processing is done so as to
+  /// establish summary information on all the jets (areas, whether
+  /// pure ghost, etc.)
+  void _post_process();
+
+};
+
+
+//----------------------------------------------------------------------
+// initialise from some generic type... Has to be made available
+// here in order for the template aspect of it to work...
+template<class L> void ClusterSequenceActiveAreaExplicitGhosts::_initialise
+         (const std::vector<L> & pseudojets, 
+          const JetDefinition & jet_def,
+	  const GhostedAreaSpec * area_spec,
+	  const std::vector<L> * ghosts,
+	  double                 ghost_area,
+	  const bool & writeout_combinations) {
+  // don't reserve space yet -- will be done below
+
+  // insert initial jets this way so that any type L that can be
+  // converted to a pseudojet will work fine (basically PseudoJet
+  // and any type that has [] subscript access to the momentum
+  // components, such as CLHEP HepLorentzVector).
+  for (unsigned int i = 0; i < pseudojets.size(); i++) {
+    PseudoJet mom(pseudojets[i]);
+    //mom.set_user_index(0); // for user's particles (user index now lost...)
+    _jets.push_back(mom);
+    _is_pure_ghost.push_back(false);
+  }
+
+  _initial_hard_n = _jets.size();
+
+  if (area_spec != NULL) {
+    _add_ghosts(*area_spec);
+  } else {
+    _add_ghosts(*ghosts, ghost_area);
+  }
+
+  if (writeout_combinations) {
+    std::cout << "# Printing particles including ghosts\n";
+    for (unsigned j = 0; j < _jets.size(); j++) {
+      printf("%5u %20.13f %20.13f %20.13e\n",
+	       j,_jets[j].rap(),_jets[j].phi_02pi(),_jets[j].kt2());
+    }
+    std::cout << "# Finished printing particles including ghosts\n";
+  }
+
+  // this will ensure that we can still point to jets without
+  // difficulties arising!
+  _jets.reserve(_jets.size()*2);
+
+  // run the clustering
+  _initialise_and_run(jet_def,writeout_combinations);
+
+  // set up all other information
+  _post_process();
+}
+
+
+inline unsigned int ClusterSequenceActiveAreaExplicitGhosts::n_hard_particles() const {return _initial_hard_n;}
+
+
+//----------------------------------------------------------------------
+/// add an explicitly specified bunch of ghosts
+template<class L> void ClusterSequenceActiveAreaExplicitGhosts::_add_ghosts (
+	  const std::vector<L> & ghosts,
+	  double                 ghost_area) {
+
+  
+  for (unsigned i = 0; i < ghosts.size(); i++) {
+    _is_pure_ghost.push_back(true);
+    _jets.push_back(ghosts[i]);
+  }
+  // and record some info about ghosts
+  _ghost_area = ghost_area;
+  _n_ghosts   = ghosts.size();
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEACTIVEAREAEXPLICITGHOSTS_HH_
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceArea.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceArea.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceArea.hh	(revision 11)
@@ -0,0 +1,223 @@
+//STARTHEADER
+// $Id: ClusterSequenceArea.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2006-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEAREA_HH__
+#define __FASTJET_CLUSTERSEQUENCEAREA_HH__
+
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceActiveArea.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequencePassiveArea.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceVoronoiArea.hh"
+#include "Utilities/Fastjet/include/fastjet/AreaDefinition.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+/// General class for user to obtain ClusterSequence with additional
+/// area information.
+///
+/// Based on the area_def, it automatically dispatches the work to the
+/// appropriate actual ClusterSequenceAreaBase-derived-class to do the
+/// real work.
+class ClusterSequenceArea : public ClusterSequenceAreaBase {
+public:
+  /// main constructor
+  template<class L> ClusterSequenceArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const AreaDefinition & area_def_in)  : _area_def(area_def_in) {
+    initialize_and_run_cswa(pseudojets, jet_def);
+  }
+
+  /// constructor with a GhostedAreaSpec
+  template<class L> ClusterSequenceArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const GhostedAreaSpec & area_spec)   : _area_def(area_spec){
+    initialize_and_run_cswa(pseudojets, jet_def);
+  }
+
+  /// constructor with a VoronoiAreaSpec
+  template<class L> ClusterSequenceArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const VoronoiAreaSpec & area_spec)   : _area_def(area_spec){
+    initialize_and_run_cswa(pseudojets, jet_def);
+  }
+
+  /// return a reference to the area definition
+  const AreaDefinition & area_def() const {return _area_def;}
+
+
+  /// return the area associated with the given jet
+  virtual double area       (const PseudoJet & jet) const {
+    return _area_base->area(jet);}
+
+  /// return the error (uncertainty) associated with the determination
+  /// of the area of this jet
+  virtual double area_error (const PseudoJet & jet) const {
+    return _area_base->area_error(jet);}
+
+  /// return the 4-vector area
+  virtual PseudoJet area_4vector(const PseudoJet & jet) const {
+    return _area_base->area_4vector(jet);}
+
+  // /// return the total area, up to |y|<maxrap, that is free of jets
+  // virtual double empty_area(double maxrap) const {
+  //   return _area_base->empty_area(maxrap);}
+  // 
+  // /// return something similar to the number of pure ghost jets
+  // /// in the given rapidity range in an active area case.
+  // /// For the local implementation we return empty_area/(0.55 pi R^2),
+  // /// based on measured properties of ghost jets with kt and cam. Note
+  // /// that the number returned is a double.
+  // virtual double n_empty_jets(double maxrap) const {
+  //   return _area_base->n_empty_jets(maxrap);
+
+  /// return the total area, in the given rap-phi range, that is free of jets
+  virtual double empty_area(const RangeDefinition & range) const {
+    return _area_base->empty_area(range);}
+
+  /// return something similar to the number of pure ghost jets
+  /// in the given rap-phi range in an active area case.
+  /// For the local implementation we return empty_area/(0.55 pi R^2),
+  /// based on measured properties of ghost jets with kt and cam. Note
+  /// that the number returned is a double.
+  virtual double n_empty_jets(const RangeDefinition & range) const {
+    return _area_base->n_empty_jets(range);
+  }
+
+  /// true if a jet is made exclusively of ghosts
+  virtual bool is_pure_ghost(const PseudoJet & jet) const {
+    return _area_base->is_pure_ghost(jet);
+  }
+
+  /// overload version of what's in the ClusterSequenceAreaBase class, which 
+  /// additionally checks compatibility between "range" and region in which
+  /// ghosts are thrown.
+  virtual void get_median_rho_and_sigma(const RangeDefinition & range, 
+                                        bool use_area_4vector,
+                                        double & median, double & sigma,
+                                        double & mean_area) const {
+    _warn_if_range_unsuitable(range);
+    ClusterSequenceAreaBase::get_median_rho_and_sigma(range, use_area_4vector,
+                                                      median, sigma, mean_area);
+  }
+
+  /// overload version of what's in the ClusterSequenceAreaBase class,
+  /// which actually just does the same thing as the base version (but
+  /// since we've overridden the 5-argument version above, we have to
+  /// override the 4-argument version too.
+  virtual void get_median_rho_and_sigma(const RangeDefinition & range, 
+                                        bool use_area_4vector,
+                                        double & median, double & sigma) const {
+    ClusterSequenceAreaBase::get_median_rho_and_sigma(range,use_area_4vector,
+                                                      median,sigma);
+  }
+
+
+  /// overload version of what's in the ClusterSequenceAreaBase class, which 
+  /// additionally checks compatibility between "range" and region in which
+  /// ghosts are thrown.
+  virtual void parabolic_pt_per_unit_area(double & a, double & b, 
+                                          const RangeDefinition & range, 
+                                          double exclude_above=-1.0, 
+                                          bool use_area_4vector=false) const {
+    _warn_if_range_unsuitable(range);
+    ClusterSequenceAreaBase::parabolic_pt_per_unit_area(
+                                a,b,range, exclude_above, use_area_4vector);
+  }
+
+
+private:
+  
+  /// print a warning if the range is unsuitable for the current
+  /// calculation of the area (e.g. because ghosts do not extend
+  /// far enough).
+  void _warn_if_range_unsuitable(const RangeDefinition & range) const;
+
+  template<class L> void initialize_and_run_cswa (
+                                 const std::vector<L> & pseudojets, 
+                                 const JetDefinition & jet_def);
+
+  std::auto_ptr<ClusterSequenceAreaBase> _area_base;
+  AreaDefinition _area_def;
+  static LimitedWarning _range_warnings;
+
+};
+
+//----------------------------------------------------------------------
+template<class L> void ClusterSequenceArea::initialize_and_run_cswa(
+           const std::vector<L> & pseudojets, 
+           const JetDefinition  & jet_def)
+ {
+  
+  ClusterSequenceAreaBase * _area_base_ptr;
+  switch(_area_def.area_type()) {
+  case active_area:
+    _area_base_ptr = new ClusterSequenceActiveArea(pseudojets, 
+                                                   jet_def, 
+                                                   _area_def.ghost_spec());
+    break;
+  case active_area_explicit_ghosts:
+    _area_base_ptr = new ClusterSequenceActiveAreaExplicitGhosts(pseudojets, 
+                                                   jet_def, 
+                                                   _area_def.ghost_spec());
+    break;
+  case voronoi_area:
+    _area_base_ptr = new ClusterSequenceVoronoiArea(pseudojets, 
+                                                   jet_def, 
+                                                   _area_def.voronoi_spec());
+    break;
+  case one_ghost_passive_area:
+    _area_base_ptr = new ClusterSequence1GhostPassiveArea(pseudojets, 
+						    jet_def, 
+						    _area_def.ghost_spec());
+    break;
+  case passive_area:
+    _area_base_ptr = new ClusterSequencePassiveArea(pseudojets, 
+						    jet_def, 
+						    _area_def.ghost_spec());
+    break;
+  default:
+    std::cerr << "Error: unrecognized area_type in ClusterSequenceArea:" 
+              << _area_def.area_type() << std::endl;
+    exit(-1);
+  }
+  // now copy across the information from the area base class
+  _area_base = std::auto_ptr<ClusterSequenceAreaBase>(_area_base_ptr);
+  transfer_from_sequence(*_area_base);
+}
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEAREA_HH__
+
+
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh	(revision 11)
@@ -0,0 +1,216 @@
+//STARTHEADER
+// $Id: ClusterSequenceAreaBase.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEAREABASE_HH__
+#define __FASTJET_CLUSTERSEQUENCEAREABASE_HH__
+
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence.hh"
+#include "Utilities/Fastjet/include/fastjet/internal/LimitedWarning.hh"
+#include "Utilities/Fastjet/include/fastjet/RangeDefinition.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+/// base class that sets interface for extensions of ClusterSequence
+/// that provide information about the area of each jet; 
+///
+/// the virtual functions here all return 0, since no area determination
+/// is implemented.
+class ClusterSequenceAreaBase : public ClusterSequence {
+public:
+  
+  /// a constructor which just carries out the construction of the
+  /// parent class
+  template<class L> ClusterSequenceAreaBase
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const bool & writeout_combinations = false) :
+           ClusterSequence(pseudojets, jet_def, writeout_combinations) {}
+
+
+  /// default constructor
+  ClusterSequenceAreaBase() {}
+
+
+  /// destructor
+  virtual ~ClusterSequenceAreaBase() {}
+
+
+  /// return the area associated with the given jet; this base class
+  /// returns 0.
+  virtual double area       (const PseudoJet & jet) const {return 0.0;}
+
+  /// return the error (uncertainty) associated with the determination
+  /// of the area of this jet; this base class returns 0.
+  virtual double area_error (const PseudoJet & jet) const {return 0.0;}
+
+  /// return a PseudoJet whose 4-vector is defined by the following integral
+  ///
+  ///       \int drap d\phi PseudoJet("rap,phi,pt=one") *
+  ///                           * Theta("rap,phi inside jet boundary")
+  ///
+  /// where PseudoJet("rap,phi,pt=one") is a 4-vector with the given
+  /// rapidity (rap), azimuth (phi) and pt=1, while Theta("rap,phi
+  /// inside jet boundary") is a function that is 1 when rap,phi
+  /// define a direction inside the jet boundary and 0 otherwise.
+  ///
+  /// This base class returns a null 4-vector.
+  virtual PseudoJet area_4vector(const PseudoJet & jet) const {
+    return PseudoJet(0.0,0.0,0.0,0.0);}
+
+  /// true if a jet is made exclusively of ghosts
+  ///
+  /// NB: most area classes do not give any explicit ghost jets, but
+  /// some do, and they should replace this function with their own
+  /// version.
+  virtual bool is_pure_ghost(const PseudoJet & jet) const {
+    return false;
+  }
+
+  /// return the total area, within range, that is free of jets
+  virtual double empty_area(const RangeDefinition & range) const;
+
+  /// return something similar to the number of pure ghost jets
+  /// in the given range in an active area case.
+  /// For the local implementation we return empty_area/(0.55 pi R^2),
+  /// based on measured properties of ghost jets with kt and cam. Note
+  /// that the number returned is a double.
+  virtual double n_empty_jets(const RangeDefinition & range) const {
+    double R = jet_def().R();
+    return empty_area(range)/(0.55*pi*R*R);
+  }
+
+  /// the median of (pt/area) for jets contained within range, 
+  /// making use also of the info on n_empty_jets
+  double median_pt_per_unit_area(const RangeDefinition & range) const;
+
+  /// the median of (pt/area_4vector) for jets contained within
+  /// making use also of the info on n_empty_jets
+  double median_pt_per_unit_area_4vector(const RangeDefinition & range) const;
+  
+  /// the function that does the work for median_pt_per_unit_area and 
+  /// median_pt_per_unit_area_4vector: 
+  /// - something_is_area_4vect = false -> use plain area
+  /// - something_is_area_4vect = true  -> use 4-vector area
+  double median_pt_per_unit_something(
+                    const RangeDefinition & range, bool use_area_4vector) const;
+
+  /// using jets withing range (and with 4-vector areas if
+  /// use_area_4vector), calculate the median pt/area, as well as an
+  /// "error" (uncertainty), which is defined as the 1-sigma
+  /// half-width of the distribution of pt/A, obtained by looking for
+  /// the point below which we have (1-0.6827)/2 of the jets
+  /// (including empty jets).
+  ///
+  /// The subtraction for a jet with uncorrected pt pt^U and area A is
+  ///
+  ///   pt^S = pt^U - median*A +- sigma*sqrt(A)
+  ///
+  /// where the error is only that associated with the fluctuations
+  /// in the noise and not that associated with the noise having 
+  /// caused changes in the hard-particle content of the jet.
+  ///
+  /// (NB: subtraction may also be done with 4-vector area of course)
+  virtual void get_median_rho_and_sigma(const RangeDefinition & range, 
+                                        bool use_area_4vector,
+                                        double & median, double & sigma,
+                                        double & mean_area) const;
+
+  /// same as the full version of get_median_rho_and_error, but without
+  /// access to the mean_area
+  virtual void get_median_rho_and_sigma(const RangeDefinition & range, 
+                                bool use_area_4vector,
+                                double & median, double & sigma) const {
+    double mean_area;
+    get_median_rho_and_sigma(range,  use_area_4vector,
+                             median,  sigma, mean_area);
+  }
+  
+
+  /// fits a form pt_per_unit_area(y) = a + b*y^2 in the range "range". 
+  /// exclude_above allows one to exclude large values of pt/area from fit. 
+  /// use_area_4vector = true uses the 4vector areas.
+  virtual void parabolic_pt_per_unit_area(double & a, double & b, 
+                                          const RangeDefinition & range, 
+                                          double exclude_above=-1.0, 
+                                          bool use_area_4vector=false) const;
+
+
+  /// return a vector of all subtracted jets, using area_4vector, given rho.
+  /// Only inclusive_jets above ptmin are subtracted and returned.
+  /// the ordering is the same as that of sorted_by_pt(cs.inclusive_jets()),
+  /// i.e. not necessarily ordered in pt once subtracted
+  std::vector<PseudoJet> subtracted_jets(const double rho,
+                                         const double ptmin=0.0) const;
+
+  /// return a vector of subtracted jets, using area_4vector.
+  /// Only inclusive_jets above ptmin are subtracted and returned.
+  /// the ordering is the same as that of sorted_by_pt(cs.inclusive_jets()),
+  /// i.e. not necessarily ordered in pt once subtracted
+  std::vector<PseudoJet> subtracted_jets(const RangeDefinition & range, 
+                                         const double ptmin=0.0) const;
+
+  /// return a subtracted jet, using area_4vector, given rho
+  PseudoJet subtracted_jet(const PseudoJet & jet,
+                           const double rho) const;
+
+  /// return a subtracted jet, using area_4vector; note
+  /// that this is potentially inefficient if repeatedly used for many
+  /// different jets, because rho will be recalculated each time
+  /// around.
+  PseudoJet subtracted_jet(const PseudoJet & jet,
+                           const RangeDefinition & range) const;
+
+  /// return the subtracted pt, given rho
+  double subtracted_pt(const PseudoJet & jet,
+                       const double rho,
+	               bool use_area_4vector=false) const;
+
+  /// return the subtracted pt; note that this is
+  /// potentially inefficient if repeatedly used for many different
+  /// jets, because rho will be recalculated each time around.
+  double subtracted_pt(const PseudoJet & jet,
+                       const RangeDefinition & range,
+	               bool use_area_4vector=false) const;
+
+
+private:
+  /// handle warning messages
+  static LimitedWarning _warnings;
+
+  /// check the jet algorithm is suitable (and if not issue a warning)
+  void _check_jet_alg_good_for_median() const;
+  
+};
+
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEAREABASE_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequencePassiveArea.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequencePassiveArea.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequencePassiveArea.hh	(revision 11)
@@ -0,0 +1,93 @@
+//STARTHEADER
+// $Id: ClusterSequencePassiveArea.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEPASSIVEAREA_HH__
+#define __FASTJET_CLUSTERSEQUENCEPASSIVEAREA_HH__
+
+
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence1GhostPassiveArea.hh"
+#include<iostream>
+#include<vector>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//using namespace std;
+
+/// Class that behaves essentially like ClusterSequence except
+/// that it also provides access to the area of a jet (which
+/// will be a random quantity... Figure out what to do about seeds 
+/// later...)
+class ClusterSequencePassiveArea : public ClusterSequence1GhostPassiveArea {
+public:
+
+  /// constructor based on JetDefinition and PassiveAreaSpec
+  template<class L> ClusterSequencePassiveArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const GhostedAreaSpec & area_spec,
+	  const bool & writeout_combinations = false) ;
+
+  /// return an empty area that's appropriate to the passive area
+  /// determination carried out
+  virtual double empty_area(const RangeDefinition & range) const;
+
+private:
+
+  /// does the initialisation and running specific to the passive
+  /// areas class
+  void _initialise_and_run_PA (const JetDefinition & jet_def,
+                               const GhostedAreaSpec & area_spec,
+                               const bool & writeout_combinations = false);
+
+};
+
+
+
+
+template<class L> ClusterSequencePassiveArea::ClusterSequencePassiveArea 
+(const std::vector<L> & pseudojets, 
+ const JetDefinition & jet_def,
+ const GhostedAreaSpec & area_spec,
+ const bool & writeout_combinations) {
+
+  // transfer the initial jets (type L) into our own array
+  _transfer_input_jets(pseudojets);
+
+  // run the clustering for passive areas
+  _initialise_and_run_PA(jet_def, area_spec, writeout_combinations);
+
+}
+
+
+  
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEPASSIVEAREA_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceVoronoiArea.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceVoronoiArea.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceVoronoiArea.hh	(revision 11)
@@ -0,0 +1,117 @@
+//STARTHEADER
+// $Id: ClusterSequenceVoronoiArea.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEVORONOIAREA_HH__
+#define __FASTJET_CLUSTERSEQUENCEVORONOIAREA_HH__
+
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/AreaDefinition.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh"
+#include <memory>
+#include <vector>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/**
+ * \class ClusterSequenceVoronoiArea
+ * Handle the computation of Voronoi jet area.
+ */
+class ClusterSequenceVoronoiArea : public ClusterSequenceAreaBase {
+public:
+  /// template ctor
+  /// \param pseudojet              list of jets (template type)
+  /// \param jet_def                jet definition
+  /// \param effective_Rfact        effective radius
+  /// \param writeout_combinations  ??????
+  template<class L> ClusterSequenceVoronoiArea
+         (const std::vector<L> & pseudojets, 
+	  const JetDefinition & jet_def,
+	  const VoronoiAreaSpec & spec = VoronoiAreaSpec(),
+	  const bool & writeout_combinations = false);
+  
+  /// default dtor
+  ~ClusterSequenceVoronoiArea();
+
+  /// return the area associated with the given jet
+  virtual inline double area(const PseudoJet & jet) const {
+    return _voronoi_area[jet.cluster_hist_index()];};
+
+  /// return a 4-vector area associated with the given jet -- stricly
+  /// this is not the exact 4-vector area, but rather an approximation
+  /// made of sums of centres of all Voronoi cells in jet, each
+  /// contributing with a normalisation equal to the area of the cell
+  virtual inline PseudoJet area_4vector(const PseudoJet & jet) const {
+    return _voronoi_area_4vector[jet.cluster_hist_index()];};
+
+  /// return the error of the area associated with the given jet
+  /// (0 by definition for a voronoi area)
+  virtual inline double area_error(const PseudoJet & jet) const {
+    return 0.0;};
+
+  /// passive area calculator -- to be defined in the .cc file (it will do
+  /// the true hard work)
+  class VoronoiAreaCalc; 
+  
+
+private:  
+  /// initialisation of the Voronoi Area
+  void _initializeVA();
+
+  std::vector<double> _voronoi_area;  ///< vector containing the result
+  std::vector<PseudoJet> _voronoi_area_4vector; ///< vector containing approx 4-vect areas
+  VoronoiAreaCalc *_pa_calc;          ///< area calculator
+  double _effective_Rfact;            ///< effective radius
+};
+
+
+
+
+/// template constructor need to be specified in the header!
+//----------------------------------------------------------------------
+template<class L> ClusterSequenceVoronoiArea::ClusterSequenceVoronoiArea
+(const std::vector<L> &pseudojets, 
+ const JetDefinition &jet_def,
+ const VoronoiAreaSpec & spec,
+ const bool & writeout_combinations) :
+  _effective_Rfact(spec.effective_Rfact()) {
+
+  // transfer the initial jets (type L) into our own array
+  _transfer_input_jets(pseudojets);
+
+  // run the clustering
+  _initialise_and_run(jet_def,writeout_combinations);
+
+  // the jet clustering's already been done, now worry about areas...
+  _initializeVA();
+}
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEVORONOIAREA_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceWithArea.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceWithArea.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/ClusterSequenceWithArea.hh	(revision 11)
@@ -0,0 +1,45 @@
+//STARTHEADER
+// $Id: ClusterSequenceWithArea.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2006-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLUSTERSEQUENCEWITHAREA_HH__
+#define __FASTJET_CLUSTERSEQUENCEWITHAREA_HH__
+
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceAreaBase.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+//----- backwards compatibility with version 2.1 ---------------
+typedef ClusterSequenceAreaBase ClusterSequenceWithArea;
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLUSTERSEQUENCEWITHAREA_HH__
+
+
Index: /trunk/Utilities/Fastjet/include/fastjet/Error.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/Error.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/Error.hh	(revision 11)
@@ -0,0 +1,65 @@
+//STARTHEADER
+// $Id: Error.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+
+#ifndef __FASTJET_ERROR_HH__
+#define __FASTJET_ERROR_HH__
+
+#include<iostream>
+#include<string>
+#include "Utilities/Fastjet/include/fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// class corresponding to errors that will be thrown by fastjet
+class Error {
+public:
+  // constructors
+  Error() {;};
+  Error(const std::string & message) {
+    _message = message; 
+    if (_print_errors) std::cerr << "fastjet::Error: "<<message << std::endl;
+  };
+
+  std::string message() const {return _message;};
+
+  static void set_print_errors(bool print_errors) {
+    _print_errors = print_errors;};
+
+private:
+  std::string _message;
+  static bool _print_errors;
+};
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_ERROR_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/GhostedAreaSpec.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/GhostedAreaSpec.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/GhostedAreaSpec.hh	(revision 11)
@@ -0,0 +1,176 @@
+//STARTHEADER
+// $Id: GhostedAreaSpec.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_GHOSTEDAREASPEC_HH__
+#define __FASTJET_GHOSTEDAREASPEC_HH__
+
+#include<vector>
+#include<string>
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include "Utilities/Fastjet/include/fastjet/internal/BasicRandom.hh"
+
+// 
+#define STATIC_GENERATOR 1
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// namespace to hold default parameters for the active area spec
+namespace gas {
+  const double def_ghost_maxrap  = 6.0;
+  const int    def_repeat        = 1;
+  const double def_ghost_area    = 0.01;
+  const double def_grid_scatter  = 1.0;
+  const double def_kt_scatter    = 0.1;
+  const double def_mean_ghost_kt = 1e-100;
+}
+
+//----------------------------------------------------------------------
+/// Class that defines the parameters that go into the measurement
+/// of active jet areas.
+class GhostedAreaSpec {
+public:
+  /// default constructor
+  GhostedAreaSpec(): _ghost_maxrap (gas::def_ghost_maxrap), 
+                    _repeat       (gas::def_repeat), 
+                    _ghost_area   (gas::def_ghost_area), 
+                    _grid_scatter (gas::def_grid_scatter), 
+                    _kt_scatter   (gas::def_kt_scatter), 
+                    _mean_ghost_kt(gas::def_mean_ghost_kt),
+                    _actual_ghost_area(-1.0) {_initialize();};
+  
+  /// explicit constructor
+  explicit GhostedAreaSpec(double ghost_maxrap, 
+                          int    repeat        = gas::def_repeat,
+                          double ghost_area    = gas::def_ghost_area,   
+                          double grid_scatter  = gas::def_grid_scatter, 
+                          double kt_scatter    = gas::def_kt_scatter,   
+                          double mean_ghost_kt = gas::def_mean_ghost_kt
+                          ): 
+    _ghost_maxrap(ghost_maxrap), 
+    _repeat(repeat), 
+    _ghost_area(ghost_area), 
+    _grid_scatter(grid_scatter),  
+    _kt_scatter(kt_scatter), 
+    _mean_ghost_kt(mean_ghost_kt),
+    _actual_ghost_area(-1.0) {_initialize();};
+
+
+  /// does the initialization of actual ghost parameters
+  void _initialize();
+
+  // for accessing values set by the user
+  inline double ghost_etamax() const {return _ghost_maxrap;};
+  inline double ghost_maxrap() const {return _ghost_maxrap;};
+  inline double ghost_area   () const {return _ghost_area   ;};
+  inline double grid_scatter() const {return _grid_scatter;};
+  inline double kt_scatter  () const {return _kt_scatter  ;};
+  inline double mean_ghost_kt() const {return _mean_ghost_kt  ;};
+  inline int    repeat      () const {return _repeat      ;};
+
+  // for accessing values 
+  inline double actual_ghost_area() const {return _actual_ghost_area;};
+  inline int    n_ghosts()          const {return _n_ghosts;};
+
+  // when explicitly modifying values, sometimes call the initializer
+  inline void set_ghost_area   (double val) {_ghost_area    = val; _initialize();};
+  inline void set_ghost_etamax(double val) {_ghost_maxrap = val; _initialize();};
+  inline void set_ghost_maxrap(double val) {_ghost_maxrap = val; _initialize();};
+  inline void set_grid_scatter(double val) {_grid_scatter   = val; };
+  inline void set_kt_scatter  (double val) {_kt_scatter     = val; };
+  inline void set_mean_ghost_kt(double val){_mean_ghost_kt  = val; };
+  inline void set_repeat      (int    val) {_repeat         = val; };
+
+  /// return nphi (ghosts layed out (-nrap, 0..nphi-1), (-nrap+1,0..nphi-1),
+  /// ... (nrap,0..nphi-1)
+  inline int nphi() const {return _nphi;}
+  inline int nrap() const {return _nrap;}
+
+  /// get all relevant information about the status of the 
+  /// random number generator, so that it can be reset subsequently
+  /// with set_random_status.
+  inline void get_random_status(std::vector<int> & __iseed) const {
+    _random_generator.get_status(__iseed);}
+
+  /// set the status of the random number generator, as obtained
+  /// previously with get_random_status. Note that the random
+  /// generator is a static member of the class, i.e. common to all
+  /// instances of the class --- so if you modify the random for this
+  /// instance, you modify it for all instances.
+  inline void set_random_status(const std::vector<int> & __iseed) {
+    _random_generator.set_status(__iseed);}
+  
+  inline void checkpoint_random() {get_random_status(_random_checkpoint);}
+  inline void restore_checkpoint_random() {set_random_status(_random_checkpoint);}
+
+  /// for a summary
+  std::string description() const;
+
+  /// push the ghost 4-momenta onto the back of the vector of PseudoJets
+  void add_ghosts(std::vector<PseudoJet> & ) const;
+
+  /// very deprecated public access to a random number 
+  /// from the internal generator
+  inline double random_at_own_risk() const {return _our_rand();};
+  /// very deprecated public access to the generator itself
+  inline BasicRandom<double> & generator_at_own_risk() const {
+    return _random_generator;}
+
+private:
+  
+  // quantities that determine nature and distribution of ghosts
+  double _ghost_maxrap;
+  int    _repeat      ;
+  double _ghost_area   ;  
+  double _grid_scatter;
+  double _kt_scatter  ;
+  double _mean_ghost_kt;
+
+  // derived quantities
+  double _actual_ghost_area, _dphi, _drap;
+  int    _n_ghosts, _nphi, _nrap;
+
+
+  std::vector<int> _random_checkpoint;
+  static BasicRandom<double> _random_generator;
+  //mutable BasicRandom<double> _random_generator;
+
+  inline double _our_rand() const {return _random_generator();};
+  
+};
+
+////----------------------------------------------------------------------
+//class 1GhostPassiveAreaSpec : public GhostedAreaSpec {
+//public:
+//}
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_GHOSTEDAREASPEC_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/JetDefinition.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/JetDefinition.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/JetDefinition.hh	(revision 11)
@@ -0,0 +1,374 @@
+//STARTHEADER
+// $Id: JetDefinition.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_JETDEFINITION_HH__
+#define __FASTJET_JETDEFINITION_HH__
+
+#include<cassert>
+#include "Utilities/Fastjet/include/fastjet/internal/numconsts.hh"
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include<string>
+#include<memory>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// return a string containing information about the release
+//  NB: (implemented in ClusterSequence.cc but defined here because
+//  this is a visible location)
+std::string fastjet_version_string();
+
+//======================================================================
+/// the various options for the algorithmic strategy to adopt in
+/// clustering events with kt and cambridge style algorithms.
+enum Strategy {
+  /// fastest form about 500..10^4
+  N2MinHeapTiled   = -4, 
+  /// fastest from about 50..500
+  N2Tiled     = -3, 
+  /// legacy
+  N2PoorTiled = -2, 
+  /// fastest below 50
+  N2Plain     = -1, 
+  /// worse even than the usual N^3 algorithms
+  N3Dumb      =  0, 
+  /// automatic selection of the best (based on N)
+  Best        =  1, 
+  /// best of the NlnN variants -- best overall for N>10^4
+  NlnN        =  2, 
+  /// legacy N ln N using 3pi coverage of cylinder
+  NlnN3pi     =  3, 
+  /// legacy N ln N using 4pi coverage of cylinder
+  NlnN4pi     =  4,
+  /// Chan's closest pair method (in a variant with 4pi coverage),
+  /// for use exclusively with the Cambridge algorithm
+  NlnNCam4pi   = 14,
+  NlnNCam2pi2R = 13,
+  NlnNCam      = 12, // 2piMultD
+  /// the plugin has been used...
+  plugin_strategy = 999
+};
+
+
+//======================================================================
+/// the various families of jet-clustering algorithm
+enum JetAlgorithm {
+  /// the longitudinally invariant kt algorithm
+  kt_algorithm=0,
+  /// the longitudinally invariant variant of the cambridge algorithm
+  /// (aka Aachen algoithm).
+  cambridge_algorithm=1,
+  /// like the k_t but with distance measures 
+  ///       dij = min(1/kti^2,1/ktj^2) Delta R_{ij}^2 / R^2
+  ///       diB = 1/kti^2
+  antikt_algorithm=2, 
+  /// like the k_t but with distance measures 
+  ///       dij = min(kti^{2p},ktj^{2p}) Delta R_{ij}^2 / R^2
+  ///       diB = 1/kti^{2p}
+  genkt_algorithm=3, 
+  /// a version of cambridge with a special distance measure for particles
+  /// whose pt is < extra_param()
+  cambridge_for_passive_algorithm=11,
+  /// a version of genkt with a special distance measure for particles
+  /// whose pt is < extra_param() [relevant for passive areas when p<=0]
+  genkt_for_passive_algorithm=13, 
+  /// any plugin algorithm supplied by the user
+  plugin_algorithm = 99
+};
+
+/// make standard Les Houches nomenclature JetAlgorithm (algorithm is general
+/// recipe without the parameters) backward-compatible with old JetFinder
+typedef JetAlgorithm JetFinder;
+
+/// provide other possible names for the Cambridge/Aachen algorithm?
+const JetAlgorithm aachen_algorithm = cambridge_algorithm;
+const JetAlgorithm cambridge_aachen_algorithm = cambridge_algorithm;
+
+//======================================================================
+/// the various recombination schemes
+enum RecombinationScheme {
+  /// summing the 4-momenta
+  E_scheme=0,
+  /// pt weighted recombination of y,phi (and summing of pt's)
+  /// with preprocessing to make things massless by rescaling E=|\vec p|
+  pt_scheme=1,
+  /// pt^2 weighted recombination of y,phi (and summing of pt's)
+  /// with preprocessing to make things massless by rescaling E=|\vec p|
+  pt2_scheme=2,
+  /// pt weighted recombination of y,phi (and summing of pt's)
+  /// with preprocessing to make things massless by rescaling |\vec p|->=E
+  Et_scheme=3,
+  /// pt^2 weighted recombination of y,phi (and summing of pt's)
+  /// with preprocessing to make things massless by rescaling |\vec p|->=E
+  Et2_scheme=4,
+  /// pt weighted recombination of y,phi (and summing of pt's), with 
+  /// no preprocessing
+  BIpt_scheme=5,
+  /// pt^2 weighted recombination of y,phi (and summing of pt's)
+  /// no preprocessing
+  BIpt2_scheme=6,
+  /// for the user's external scheme
+  external_scheme = 99
+};
+
+
+
+
+// forward declaration, needed in order to specify interface for the
+// plugin.
+class ClusterSequence;
+
+
+
+
+//======================================================================
+/// class that is intended to hold a full definition of the jet
+/// clusterer
+class JetDefinition {
+  
+public:
+
+  /// forward declaration of a class that allows the user to introduce
+  /// their own plugin 
+  class Plugin;
+
+  // forward declaration of a class that will provide the
+  // recombination scheme facilities and/or allow a user to
+  // extend these facilities
+  class Recombiner;
+
+  /// constructor to fully specify a jet-definition (together
+  /// with information about how algorithically to run it). 
+  ///
+  JetDefinition(JetAlgorithm jet_algorithm, 
+                double R, 
+                Strategy strategy,
+                RecombinationScheme recomb_scheme = E_scheme) :
+    _jet_algorithm(jet_algorithm), _Rparam(R), _strategy(strategy) {
+    // the largest sensible value for R
+    assert(_Rparam <= 0.5*pi);
+    assert(_jet_algorithm != plugin_algorithm &&
+           _strategy   != plugin_strategy);
+    _plugin = NULL;
+    set_recombination_scheme(recomb_scheme);
+  }
+  
+
+  /// constructor with alternative ordering or arguments -- note that
+  /// we have not provided a default jet finder, to avoid ambiguous
+  /// JetDefinition() constructor.
+  JetDefinition(JetAlgorithm jet_algorithm = kt_algorithm, 
+                double R = 1.0, 
+                RecombinationScheme recomb_scheme = E_scheme,
+                Strategy strategy = Best) {
+    *this = JetDefinition(jet_algorithm, R, strategy, recomb_scheme);
+  }
+
+
+  /// constructor in a form that allows the user to provide a pointer
+  /// to an external recombiner class (which must remain valid for the
+  /// life of the JetDefinition object).
+  JetDefinition(JetAlgorithm jet_algorithm, 
+                double R, 
+                const Recombiner * recombiner,
+                Strategy strategy = Best) {
+    *this = JetDefinition(jet_algorithm, R, strategy, external_scheme);
+    _recombiner = recombiner;
+  }
+
+  /// constructor based on a pointer to a user's plugin; the object
+  /// pointed to must remain valid for the whole duration of existence
+  /// of the JetDefinition and any related ClusterSequences
+  JetDefinition(const Plugin * plugin) {
+    _plugin = plugin;
+    _strategy = plugin_strategy;
+    _Rparam = _plugin->R();
+    _jet_algorithm = plugin_algorithm;
+    set_recombination_scheme(E_scheme);
+  }
+
+  /// set the recombination scheme to the one provided
+  void set_recombination_scheme(RecombinationScheme);
+
+  /// set the recombiner class to the one provided
+  void set_recombiner(const Recombiner * recomb) {
+    _recombiner = recomb;
+    _default_recombiner = DefaultRecombiner(external_scheme);
+  }
+
+  /// return a pointer to the plugin 
+  const Plugin * plugin() const {return _plugin;};
+
+  /// return information about the definition...
+  JetAlgorithm jet_algorithm  () const {return _jet_algorithm  ;}
+  /// same as above for backward compatibility
+  JetAlgorithm jet_finder     () const {return _jet_algorithm  ;}
+  double    R           () const {return _Rparam      ;}
+  // a general purpose extra parameter, whose meaning depends on
+  // the algorithm, and may often be unused.
+  double    extra_param () const {return _extra_param ;}
+  Strategy  strategy    () const {return _strategy    ;}
+  RecombinationScheme recombination_scheme() const {
+    return _default_recombiner.scheme();}
+
+  /// (re)set the jet finder
+  void set_jet_algorithm(JetAlgorithm njf) {_jet_algorithm = njf;}
+  /// same as above for backward compatibility
+  void set_jet_finder(JetAlgorithm njf)    {_jet_algorithm = njf;}
+  /// (re)set the general purpose extra parameter
+  void set_extra_param(double xtra_param) {_extra_param = xtra_param;}
+
+  /// return a pointer to the currently defined recombiner (it may
+  /// be the internal one)
+  const Recombiner * recombiner() const {
+    return _recombiner == 0 ? & _default_recombiner : _recombiner;}
+
+  /// return a textual description of the current jet definition 
+  std::string description() const;
+
+
+public:
+  //======================================================================
+  /// An abstract base class that will provide the recombination scheme
+  /// facilities and/or allow a user to extend these facilities
+  class Recombiner {
+  public:
+    /// return a textual description of the recombination scheme
+    /// implemented here
+    virtual std::string description() const = 0;
+    
+    /// recombine pa and pb and put result into pab
+    virtual void recombine(const PseudoJet & pa, const PseudoJet & pb, 
+                           PseudoJet & pab) const = 0;
+
+    /// routine called to preprocess each input jet (to make all input
+    /// jets compatible with the scheme requirements (e.g. massless).
+    virtual void preprocess(PseudoJet & p) const {};
+    
+    /// a destructor to be replaced if necessary in derived classes...
+    virtual ~Recombiner() {};
+
+    /// pa += pb in the given recombination scheme. Not virtual -- the
+    /// user should have no reason to want to redefine this!
+    inline void plus_equal(PseudoJet & pa, const PseudoJet & pb) const {
+      // put result in a temporary location in case the recombiner
+      // does something funny (ours doesn't, but who knows about the
+      // user's)
+      PseudoJet pres; 
+      recombine(pa,pb,pres);
+      pa = pres;
+    }
+
+  };
+  
+  
+  //======================================================================
+  /// A class that will provide the recombination scheme facilities and/or
+  /// allow a user to extend these facilities
+  class DefaultRecombiner : public Recombiner {
+  public:
+    DefaultRecombiner(RecombinationScheme recomb_scheme = E_scheme) : 
+      _recomb_scheme(recomb_scheme) {}
+    
+    virtual std::string description() const;
+    
+    /// recombine pa and pb and put result into pab
+    virtual void recombine(const PseudoJet & pa, const PseudoJet & pb, 
+                           PseudoJet & pab) const;
+
+    virtual void preprocess(PseudoJet & p) const;
+
+    /// return the index of the recombination scheme
+    RecombinationScheme scheme() const {return _recomb_scheme;}
+    
+  private:
+    RecombinationScheme _recomb_scheme;
+  };
+
+
+  //======================================================================
+  /// a class that allows a user to introduce their own "plugin" jet
+  /// finder
+  class Plugin{
+  public:
+    /// return a textual description of the jet-definition implemented
+    /// in this plugin
+    virtual std::string description() const = 0;
+    
+    /// given a ClusterSequence that has been filled up with initial
+    /// particles, the following function should fill up the rest of the
+    /// ClusterSequence, using the following member functions of
+    /// ClusterSequence:
+    ///   - plugin_do_ij_recombination(...)
+    ///   - plugin_do_iB_recombination(...)
+    virtual void run_clustering(ClusterSequence &) const = 0;
+    
+    virtual double R() const = 0;
+    
+    /// return true if there is specific support for the measurement
+    /// of passive areas, in the sense that areas determined from all
+    /// particles below the ghost separation scale will be a passive
+    /// area. [If you don't understand this, ignore it!]
+    virtual bool supports_ghosted_passive_areas() const {return false;}
+
+    /// set the ghost separation scale for passive area determinations
+    /// in future runs (strictly speaking that makes the routine
+    /// a non const, so related internal info must be stored as a mutable)
+    virtual void set_ghost_separation_scale(double scale) const;
+    virtual double ghost_separation_scale() const {return 0.0;}
+
+    /// a destructor to be replaced if necessary in derived classes...
+    virtual ~Plugin() {};
+  };
+
+private:
+
+
+  JetAlgorithm _jet_algorithm;
+  double    _Rparam;
+  double    _extra_param ; ///< parameter whose meaning varies according to context
+  Strategy  _strategy  ;
+
+  const Plugin * _plugin;
+
+  // when we use our own recombiner it's useful to point to it here
+  // so that we don't have to worry about deleting it etc...
+  DefaultRecombiner _default_recombiner;
+  const Recombiner * _recombiner;
+
+};
+
+
+
+
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_JETDEFINITION_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/PseudoJet.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/PseudoJet.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/PseudoJet.hh	(revision 11)
@@ -0,0 +1,320 @@
+//STARTHEADER
+// $Id: PseudoJet.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_PSEUDOJET_HH__
+#define __FASTJET_PSEUDOJET_HH__
+
+#include<valarray>
+#include<vector>
+#include<cassert>
+#include<cmath>
+#include<iostream>
+#include "Utilities/Fastjet/include/fastjet/internal/numconsts.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//using namespace std;
+
+/// Used to protect against parton-level events where pt can be zero
+/// for some partons, giving rapidity=infinity. KtJet fails in those cases.
+const double MaxRap = 1e5;
+
+/// Class to contain pseudojets, including minimal information of use to
+/// to jet-clustering routines.
+class PseudoJet {
+
+ public:
+  PseudoJet() {};
+  /// construct a pseudojet from explicit components
+  PseudoJet(const double px, const double py, const double pz, const double E);
+  /// constructor from any object that has px,py,pz,E = some_four_vector[0--3],
+  template <class L> PseudoJet(const L & some_four_vector) ;
+
+  // first "const double &" says that result is a reference to the
+  // stored value and that we will not change that stored value.
+  //
+  // second "const" says that "this" will not be modified by these
+  // functions.
+  inline double E()   const {return _E;}
+  inline double e()   const {return _E;} // like CLHEP
+  inline double px()  const {return _px;}
+  inline double py()  const {return _py;}
+  inline double pz()  const {return _pz;}
+
+  /// returns phi (in the range 0..2pi)
+  inline const double phi() const {return phi_02pi();}
+
+  /// returns phi in the range -pi..pi
+  inline const double phi_std()  const {
+    return _phi > pi ? _phi-twopi : _phi;}
+
+  /// returns phi in the range 0..2pi
+  inline const double phi_02pi() const {return _phi;}
+
+  /// returns the rapidity or some large value when the rapidity
+  /// is infinite
+  inline double rap() const {return _rap;}
+
+  /// the same as rap()
+  inline double rapidity() const {return _rap;} // like CLHEP
+
+  /// returns the pseudo-rapidity or some large value when the
+  /// rapidity is infinite
+  double pseudorapidity() const;
+  double eta() const {return pseudorapidity();}
+
+  /// returns the squared transverse momentum
+  inline double kt2() const {return _kt2;}
+  /// returns the squared transverse momentum
+  inline double perp2() const {return _kt2;}  // like CLHEP
+  /// returns the scalar transverse momentum
+  inline double  perp() const {return sqrt(_kt2);}    // like CLHEP
+  /// returns the squared invariant mass // like CLHEP
+  inline double  m2() const {return (_E+_pz)*(_E-_pz)-_kt2;}    
+  /// returns the squared transverse mass = kt^2+m^2
+  inline double mperp2() const {return (_E+_pz)*(_E-_pz);}
+  /// returns the transverse mass = sqrt(kt^2+m^2)
+  inline double mperp() const {return sqrt(std::abs(mperp2()));}
+  /// returns the invariant mass 
+  /// (If m2() is negative then -sqrt(-m2()) is returned, as in CLHEP)
+  inline double  m() const;    
+  /// returns component i, where X==0, Y==1, Z==2, E==3
+  double operator () (int i) const ; 
+  /// returns component i, where X==0, Y==1, Z==2, E==3
+  inline double operator [] (int i) const { return (*this)(i); }; // this too
+
+  // taken from CLHEP
+  enum { X=0, Y=1, Z=2, T=3, NUM_COORDINATES=4, SIZE=NUM_COORDINATES };
+
+
+  /// transform this jet (given in the rest frame of prest) into a jet
+  /// in the lab frame [NOT FULLY TESTED]
+  PseudoJet & boost(const PseudoJet & prest);
+  /// transform this jet (given in lab) into a jet in the rest
+  /// frame of ps  [NOT FULLY TESTED]
+  PseudoJet & unboost(const PseudoJet & prest);
+
+  /// return the cluster_hist_index, intended to be used by clustering
+  /// routines.
+  inline const int & cluster_hist_index() const {return _cluster_hist_index;}
+  /// set the cluster_hist_index, intended to be used by clustering routines.
+  inline void set_cluster_hist_index(const int index) {_cluster_hist_index = index;}
+
+  /// alternative name for cluster_hist_index() [perhaps more meaningful]
+  inline const int cluster_sequence_history_index() const {
+    return cluster_hist_index();}
+  /// alternative name for set_cluster_hist_index(...) [perhaps more
+  /// meaningful]
+  inline void set_cluster_sequence_history_index(const int index) {
+    set_cluster_hist_index(index);}
+
+
+  /// return the user_index, intended to allow the user to "add" information
+  inline const int & user_index() const {return _user_index;}
+  /// set the user_index, intended to allow the user to "add" information
+  inline void set_user_index(const int index) {_user_index = index;}
+
+  /// return a valarray containing the four-momentum (components 0-2
+  /// are 3-mom, component 3 is energy).
+  std::valarray<double> four_mom() const;
+
+  /// returns kt distance (R=1) between this jet and another
+  double kt_distance(const PseudoJet & other) const;
+
+  /// returns squared cylinder (rap-phi) distance between this jet and another
+  double plain_distance(const PseudoJet & other) const;
+  /// returns squared cylinder (rap-phi) distance between this jet and
+  /// another
+  inline double squared_distance(const PseudoJet & other) const {
+    return plain_distance(other);}
+
+  //// this seemed to compile except if it was used
+  //friend inline double 
+  //  kt_distance(const PseudoJet & jet1, const PseudoJet & jet2) { 
+  //                                      return jet1.kt_distance(jet2);}
+
+  /// returns distance between this jet and the beam
+  inline double beam_distance() const {return _kt2;}
+
+
+  void operator*=(double);
+  void operator/=(double);
+  void operator+=(const PseudoJet &);
+  void operator-=(const PseudoJet &);
+
+  /// reset the 4-momentum according to the supplied components and
+  /// put the user and history indices back to their default values
+  inline void reset(double px, double py, double pz, double E);
+  
+  /// reset the PseudoJet to be equal to psjet (including its
+  /// indices); NB if the argument is derived from a PseudoJet then
+  /// the "reset" used will be the templated version (which does not
+  /// know about indices...)
+  inline void reset(const PseudoJet & psjet) {
+    (*this) = psjet;
+  }
+
+  /// reset the 4-momentum according to the supplied generic 4-vector
+  /// (accessible via indexing, [0]==px,...[3]==E) and put the user
+  /// and history indices back to their default values.
+  template <class L> inline void reset(const L & some_four_vector) {
+    reset(some_four_vector[0], some_four_vector[1],
+          some_four_vector[2], some_four_vector[3]);
+  }
+
+ private: 
+  // NB: following order must be kept for things to behave sensibly...
+  double _px,_py,_pz,_E;
+  double _phi, _rap, _kt2; 
+  int    _cluster_hist_index, _user_index;
+  /// calculate phi, rap, kt2 based on the 4-momentum components
+  void _finish_init();
+  /// set the indices to default values
+  void _reset_indices();
+
+  //vertex_type * vertex0, vertex1;
+};
+
+
+//----------------------------------------------------------------------
+// routines for basic binary operations
+
+PseudoJet operator+(const PseudoJet &, const PseudoJet &);
+PseudoJet operator-(const PseudoJet &, const PseudoJet &);
+PseudoJet operator*(double, const PseudoJet &);
+PseudoJet operator*(const PseudoJet &, double);
+PseudoJet operator/(const PseudoJet &, double);
+
+/// returns true if the momenta of the two input jets are identical
+bool have_same_momentum(const PseudoJet &, const PseudoJet &);
+
+/// return a pseudojet with the given pt, y, phi and mass
+PseudoJet PtYPhiM(double pt, double y, double phi, double m = 0.0);
+
+//----------------------------------------------------------------------
+// Routines to do with providing sorted arrays of vectors.
+
+/// return a vector of jets sorted into decreasing transverse momentum
+std::vector<PseudoJet> sorted_by_pt(const std::vector<PseudoJet> & jets);
+
+/// return a vector of jets sorted into increasing rapidity
+std::vector<PseudoJet> sorted_by_rapidity(const std::vector<PseudoJet> & jets);
+
+/// return a vector of jets sorted into decreasing energy
+std::vector<PseudoJet> sorted_by_E(const std::vector<PseudoJet> & jets);
+
+//----------------------------------------------------------------------
+// some code to help sorting
+
+/// sort the indices so that values[indices[0->n-1]] is sorted
+/// into increasing order 
+void sort_indices(std::vector<int> & indices, 
+		  const std::vector<double> & values);
+
+/// given a vector of values with a one-to-one correspondence with the
+/// vector of objects, sort objects into an order such that the
+/// associated values would be in increasing order (but don't actually
+/// touch the values vector in the process).
+template<class T> std::vector<T> objects_sorted_by_values(const std::vector<T> & objects, 
+					      const std::vector<double> & values);
+
+/// a class that helps us carry out indexed sorting.
+class IndexedSortHelper {
+public:
+  inline IndexedSortHelper (const std::vector<double> * reference_values) {
+    _ref_values = reference_values;
+  };
+  inline int operator() (const int & i1, const int & i2) const {
+    return  (*_ref_values)[i1] < (*_ref_values)[i2];
+  };
+private:
+  const std::vector<double> * _ref_values;
+};
+
+
+//----------------------------------------------------------------------
+/// constructor from any object that has px,py,pz,E = some_four_vector[0--3],
+// NB: do not know if it really needs to be inline, but when it wasn't
+//     linking failed with g++ (who knows what was wrong...)
+template <class L> inline  PseudoJet::PseudoJet(const L & some_four_vector) {
+
+  _px = some_four_vector[0];
+  _py = some_four_vector[1];
+  _pz = some_four_vector[2];
+  _E  = some_four_vector[3];
+  _finish_init();
+  // some default values for these two indices
+  _reset_indices();
+}
+
+
+//----------------------------------------------------------------------
+inline void PseudoJet::_reset_indices() { 
+  set_cluster_hist_index(-1);
+  set_user_index(-1);
+}
+
+//----------------------------------------------------------------------
+/// specialization of the "reset" template for case where something
+/// is reset to a pseudojet -- it then takes the user and history
+/// indices from the psjet
+// template<> inline void PseudoJet::reset<PseudoJet>(const PseudoJet & psjet) {
+//   (*this) = psjet;
+// }
+
+////// fun and games...
+////template<class L> class FJVector : public L {
+//////  /** Default Constructor: create jet with no constituents */
+//////  Vector<L>();
+////
+////};
+////
+
+// taken literally from CLHEP
+inline double PseudoJet::m() const {
+  double mm = m2();
+  return mm < 0.0 ? -std::sqrt(-mm) : std::sqrt(mm);
+}
+
+
+inline void PseudoJet::reset(double px, double py, double pz, double E) {
+  _px = px;
+  _py = py;
+  _pz = pz;
+  _E  = E;
+  _finish_init();
+  _reset_indices();
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_PSEUDOJET_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/RangeDefinition.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/RangeDefinition.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/RangeDefinition.hh	(revision 11)
@@ -0,0 +1,126 @@
+//STARTHEADER
+// $Id: RangeDefinition.hh,v 1.1 2008-11-06 14:32:08 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_RANGEDEFINITION_HH__
+#define __FASTJET_RANGEDEFINITION_HH__
+
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include<sstream>
+#include<iostream>
+#include<string>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+//
+/// class for holding a range definition specification, given by limits
+/// on rapidity and azimuth.
+///
+class RangeDefinition {
+public:
+  /// default constructor
+  RangeDefinition() {}
+
+  /// constructor for a range definition given by |y|<rapmax
+  RangeDefinition(double rapmax) {
+                     assert ( rapmax > 0.0 );
+                     _rapmax = rapmax;
+		     _rapmin = -rapmax;
+		     _phimin = 0.0;
+		     _phimax = twopi;
+		     _total_area = 2.0*rapmax*twopi; }
+  
+  /// destructor does nothing
+  virtual ~RangeDefinition() {}
+     
+  /// constructor for a range definition given by 
+  /// rapmin <= y <= rapmax, phimin <= phi <= phimax
+  RangeDefinition(double rapmin, double rapmax, 
+                  double phimin = 0.0, double phimax = twopi) {
+                     assert ( rapmin < rapmax);
+                     assert ( phimin < phimax);
+                     assert ( phimin >= 0.0 );
+                     _rapmax = rapmax;
+		     _rapmin = rapmin;
+		     _phimin = phimin;
+		     _phimax = phimax;
+		     _total_area = (_rapmax - _rapmin)*(_phimax - _phimin); }
+
+
+  /// return bool according to whether the jet is within the given range
+  inline bool is_in_range(const PseudoJet & jet) const {
+    double rap = jet.rap();
+    double phi = jet.phi();
+    return is_in_range(rap,phi);
+  }
+  
+  /// return bool according to whether a (rap,phi) point is in range
+  virtual inline bool is_in_range(double rap, double phi) const {
+    return  ( rap >= _rapmin && 
+              rap <= _rapmax &&
+              phi >= _phimin &&
+              phi <= _phimax );
+  }
+
+  /// return the minimal and maximal rapidity of this range; remember to 
+  /// replace this if you write a derived class with more complex ranges;
+  virtual inline void get_rap_limits(double & rapmin, double & rapmax) const {
+    rapmin = _rapmin;
+    rapmax = _rapmax;
+  }
+  
+  /// area of the range region
+  virtual inline double area() const { return _total_area; }
+  
+  /// textual description of range
+  virtual inline std::string description() const {
+    std::ostringstream ostr;
+    ostr << "Range: " << _rapmin << " <= y <= "   << _rapmax << ", "
+                      << _phimin << " <= phi <= " << _phimax ;
+    return ostr.str();
+}
+
+protected:
+  double _total_area;  // total area of specified range
+
+  /// calculate, and set  _total_area, by calculating which of points on 
+  /// a grid (npoints * npoints from -rapmax..rapmax,0..2pi) are contained
+  /// in the range; it takes a reasonable time with rapmax = 10,
+  /// npoints = 100.
+  void _numerical_total_area(double rapmax, int npoints) ;
+
+private:
+  double _rapmin,_rapmax,_phimin,_phimax;
+
+};
+
+FASTJET_END_NAMESPACE        // defined in fastjet/internal/base.hh
+
+#endif // __FASTJET_RANGEDEFINITION_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/config.h
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/config.h	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/config.h	(revision 11)
@@ -0,0 +1,12 @@
+#ifndef __FASTJET_CONFIG_H__
+#define __FASTJET_CONFIG_H__
+
+// by default, use an automatically generated config_auto.h
+// unless it's a windows machine in which case
+#ifndef WIN32
+#include "config_auto.h"
+#else 
+#include "fastjet/config_win.h"
+#endif // WIN32
+
+#endif // __FASTJET_CONFIG_H__
Index: /trunk/Utilities/Fastjet/include/fastjet/config_auto.h
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/config_auto.h	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/config_auto.h	(revision 11)
@@ -0,0 +1,68 @@
+/* include/fastjet/config_auto.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* The CDFJetClu and CDFMidPoint plugins are enabled */
+#define ENABLE_PLUGIN_CDFCONES 
+
+/* The PxCone plugin is enabled */
+/* #undef ENABLE_PLUGIN_PXCONE */
+
+/* The SISCone plugin is enabled */
+#define ENABLE_PLUGIN_SISCONE 
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "fastjet"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "FastJet"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "FastJet 2.3.4"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "fastjet"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.3.4"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "2.3.4"
Index: /trunk/Utilities/Fastjet/include/fastjet/config_win.h
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/config_win.h	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/config_win.h	(revision 11)
@@ -0,0 +1,11 @@
+#define PACKAGE_STRING  "FastJet 2.3.4"
+#define PACKAGE_VERSION  "2.3.4"
+
+/* The CDFJetClu and CDFMidPoint plugins are enabled by default*/
+#define ENABLE_PLUGIN_CDFCONES 
+
+/* The PxCone plugin is disabled by default*/
+#undef ENABLE_PLUGIN_PXCONE
+
+/* The SISCone plugin is enabled by default*/
+#define ENABLE_PLUGIN_SISCONE 
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/BasicRandom.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/BasicRandom.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/BasicRandom.hh	(revision 11)
@@ -0,0 +1,181 @@
+// Simple random number generator class taken from nlojet++.
+// Some doxygen-style comments added by Gavin Salam, August 2006.
+// $Id: BasicRandom.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+//  Copyright (C) 2002 Zoltan Nagy
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#ifndef __FASTJET_BASICRANDOM_HH__
+#define __FASTJET_BASICRANDOM_HH__ 1
+
+//   Standard includes
+#include <iostream>
+#include <vector>
+#include <cassert>
+#include "Utilities/Fastjet/include/fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+template<typename _Tp> class BasicRandom {
+public:
+  typedef _Tp          value_type;
+  typedef unsigned int size_type;
+  typedef value_type*  pointer;
+  
+  //   give pseudo random numbers
+  value_type operator() ();
+  void       operator() (size_type, pointer);
+
+  //   (re)initialize the random number generator
+  void randomize(void *);
+
+  //   minimum and maximum values
+  static value_type min();
+  static value_type max();
+
+  //   print the informations about the generator to the stream
+  void print_info(std::ostream& __os = std::cout);
+};
+
+//   default random generator
+int __default_random_generator(int *__iseed); 
+
+
+//   specializations
+template<>
+class BasicRandom<int>
+{
+public:
+  typedef int          value_type;
+  typedef unsigned int size_type;
+  typedef value_type*  pointer;
+  
+  // constructors
+  explicit BasicRandom(int __s1 = 12345, int __s2 = 67890) {
+    _M_iseed[0] = __s1;
+    _M_iseed[1] = __s2;
+  }
+    
+  //   give pseudo random numbers
+  value_type operator() () { 
+    return __default_random_generator(_M_iseed);
+  }
+  
+  void operator() (size_type __n, pointer __res) {
+    for(size_type __i = 0; __i < __n; __i++) 
+      __res[__i] = __default_random_generator(_M_iseed);
+  }
+
+  //   (re)initialize the random number generator
+  void randomize(void *__iseed) {
+    int *__new_seed = (int*) __iseed;
+    _M_iseed[0] = __new_seed[0];
+    _M_iseed[1] = __new_seed[1];
+  }
+
+  void set_status(const std::vector<int> & __iseed) {
+    assert(__iseed.size() >= 2);
+    _M_iseed[0] = __iseed[0];
+    _M_iseed[1] = __iseed[1];
+  }
+
+  void get_status(std::vector<int> & __iseed) {
+    __iseed.resize(2);
+    __iseed[0] = _M_iseed[0];
+    __iseed[1] = _M_iseed[1];
+  }
+  
+  //   minimum and maximum values
+  inline static value_type min() { return 0;}
+  inline static value_type max() { return 2147483647;}
+
+  //   print the informations about the generator to the stream
+  void print_info(std::ostream& __os = std::cout) {
+    __os<<"BasicRandom<int> : "<<_M_iseed[0]<<", "<<_M_iseed[1]<<std::endl;
+  }
+  
+private:
+  int _M_iseed[2];
+};
+  
+
+/// template specialization (double) for the BasicRandom template class. 
+template<> class BasicRandom<double> {
+public:
+  typedef double       value_type;
+  typedef unsigned int size_type;
+  typedef value_type*  pointer;
+  
+  /// constructor that takes two integers to specify the seed
+  explicit BasicRandom(int __s1 = 12345, int __s2 = 67890) {
+    _M_iseed[0] = __s1;
+    _M_iseed[1] = __s2;
+  }
+    
+  /// return a single pseudorandom double number, in the range 0.0 to 1.0
+  /// (not sure whether this range is open or closed)
+  value_type operator() () { 
+    return 4.6566128752457969241e-10*__default_random_generator(_M_iseed);
+  }
+  
+  /// given a pointer __res to the beginning of an array, fill that array
+  /// with __n random numbers
+  void operator() (size_type __n, pointer __res) {
+    for(size_type __i = 0; __i < __n; __i++) 
+      __res[__i] = this -> operator()(); 
+  }
+
+  ///  (re)initialize the random number generator from an array of seeds
+  void randomize(void *__iseed) {
+    int *__new_seed = (int*) __iseed;
+    _M_iseed[0] = __new_seed[0];
+    _M_iseed[1] = __new_seed[1];
+  }
+  
+  void set_status(const std::vector<int> & __iseed) {
+    assert(__iseed.size() >= 2);
+    _M_iseed[0] = __iseed[0];
+    _M_iseed[1] = __iseed[1];
+  }
+
+  void get_status(std::vector<int> & __iseed) {
+    __iseed.resize(2);
+    __iseed[0] = _M_iseed[0];
+    __iseed[1] = _M_iseed[1];
+  }
+  
+  /// minimum value returned by the generator
+  inline static value_type min() { return 0.0;}
+  /// maximum value returned by the generator
+  inline static value_type max() { return 1.0;}
+
+  ///  print information about the generator to the stream
+  void print_info(std::ostream& __os = std::cout) {
+    __os<<"BasicRandom<double> : "<<_M_iseed[0]<<", "<<_M_iseed[1]<<std::endl;
+  }
+  
+private:
+  int _M_iseed[2];
+};
+  
+//   globally defined random number generator
+extern BasicRandom<int>     _G_random_int;
+extern BasicRandom<double>  _G_random_double;
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_BASICRANDOM_HH__
+
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/ClosestPair2D.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/ClosestPair2D.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/ClosestPair2D.hh	(revision 11)
@@ -0,0 +1,234 @@
+//STARTHEADER
+// $Id: ClosestPair2D.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLOSESTPAIR2D__HH__
+#define __FASTJET_CLOSESTPAIR2D__HH__
+
+#include<vector>
+#include<stack>
+#include<iostream>
+#include "Utilities/Fastjet/include/fastjet/internal/ClosestPair2DBase.hh"
+#include "Utilities/Fastjet/include/fastjet/internal/SearchTree.hh"
+#include "Utilities/Fastjet/include/fastjet/internal/MinHeap.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+/// concrete implementation for finding closest pairs in 2D -- will
+/// use Chan's (hopefully efficient) shuffle based structures
+class ClosestPair2D : public ClosestPair2DBase {
+public:
+  /// constructor from a vector of 2D positions -- number of objects
+  /// after insertion and deletion must never exceed positions.size();
+  /// objects are given IDs that correspond to their index in the vector 
+  /// of positions
+  ClosestPair2D(const std::vector<Coord2D> & positions, 
+		const Coord2D & left_corner, const Coord2D & right_corner) {
+    _initialize(positions, left_corner, right_corner, positions.size());
+  };
+
+  /// constructor which allows structure to grow beyond positions.size(), up
+  /// to max_size
+  ClosestPair2D(const std::vector<Coord2D> & positions, 
+		const Coord2D & left_corner, const Coord2D & right_corner,
+		const unsigned int max_size) {
+    _initialize(positions, left_corner, right_corner, max_size);
+  };
+
+  /// provides the IDs of the closest pair as well as the distance between
+  /// them
+  void closest_pair(unsigned int & ID1, unsigned int & ID2, 
+		    double & distance2) const;
+
+  /// removes the entry labelled by ID from the object;
+  void remove(unsigned int ID);
+ 
+  /// inserts the position into the closest pair structure and returns the
+  /// ID that has been allocated for the object.
+  unsigned int insert(const Coord2D &);
+
+  /// removes ID1 and ID2 and inserts position, returning the ID 
+  /// corresponding to position...
+  virtual unsigned int replace(unsigned int ID1, unsigned int ID2, 
+			       const Coord2D & position);
+
+  /// replaces IDs_to_remove with points at the new_positions
+  /// indicating the IDs allocated to the new points in new_IDs
+  virtual void replace_many(const std::vector<unsigned int> & IDs_to_remove,
+			    const std::vector<Coord2D> & new_positions,
+			    std::vector<unsigned int> & new_IDs);
+
+  // mostly for checking how things are working...
+  inline void print_tree_depths(std::ostream & outdev) const {
+    outdev    << _trees[0]->max_depth() << " "
+	      << _trees[1]->max_depth() << " "
+	      << _trees[2]->max_depth() << "\n";
+  };
+
+  unsigned int size();
+
+private:
+  
+  void _initialize(const std::vector<Coord2D> & positions, 
+	      const Coord2D & left_corner, const Coord2D & right_corner,
+	      const unsigned int max_size);
+
+  static const unsigned int _nshift = 3;
+
+  class Point; // will be defined below
+
+  /// since sets of three objects will crop up repeatedly, useful
+  /// to have a triplet class?
+  template<class T> class triplet {
+  public:
+    inline const T & operator[](unsigned int i) const {return _contents[i];};
+    inline       T & operator[](unsigned int i)       {return _contents[i];};
+  private:
+    T _contents[_nshift];
+  };
+
+
+  /// class that will take care of ordering of shuffles for us
+  class Shuffle {
+  public:
+    unsigned int x, y;
+    Point * point;
+    bool operator<(const Shuffle &) const;
+    void operator+=(unsigned int shift) {x += shift; y+= shift;};
+  };
+
+  typedef SearchTree<Shuffle>     Tree;
+  typedef Tree::circulator        circulator;
+  typedef Tree::const_circulator  const_circulator;
+
+
+  triplet<std::auto_ptr<Tree> >  _trees;
+  std::auto_ptr<MinHeap> _heap;
+  std::vector<Point>     _points;
+  std::stack<Point *>    _available_points;
+
+  /// points that are "under review" in some way
+  std::vector<Point *>   _points_under_review;
+
+  // different statuses for review
+  static const unsigned int _remove_heap_entry = 1;
+  static const unsigned int _review_heap_entry = 2;
+  static const unsigned int _review_neighbour  = 4;
+
+  /// add a label to a point as to the nature of review needed
+  /// (includes adding it to list of points needing review) [doesn't
+  /// affect other labels already set for the point]
+  void _add_label(Point * point, unsigned int review_flag);
+
+  /// sets the label for the point to be exclusively this 
+  /// review flag (and adds it to list of points needing review
+  /// if not already there)
+  void _set_label(Point * point, unsigned int review_flag);
+
+  /// for all entries of the _points_under_review[] vector, carry out
+  /// the actions indicated by its review flag; the points are
+  /// then removed from _points_under_review[] and their flags
+  /// set to zero
+  void _deal_with_points_to_review();
+
+  /// carry out the search-tree related operations of point removal
+  void _remove_from_search_tree(Point * point_to_remove);
+
+  /// carry out the search-tree related operations of point insertion
+  void _insert_into_search_tree(Point * new_point);
+
+  /// takes a point and creates a shuffle with the given shift
+  void _point2shuffle(Point & , Shuffle & , unsigned int shift);
+
+  /// pieces needed for converting coordinates to integer
+  Coord2D _left_corner;
+  double _range;
+
+  int _ID(const Point *) const;
+
+  triplet<unsigned int> _shifts;     // absolute shifts
+  triplet<unsigned int> _rel_shifts; // shifts relative to previous shift
+
+  unsigned int _cp_search_range;
+};
+
+
+//----------------------------------------------------------------------
+/// class for representing all info needed about a point
+class ClosestPair2D::Point {
+public:
+  /// the point's coordinates
+  Coord2D coord;
+  /// a pointer to its closest neighbour in our structure
+  Point * neighbour;
+  /// the corresponding squared distance
+  double  neighbour_dist2;
+  /// circulators for each of the shifts of the shuffles
+  triplet<circulator> circ;
+
+  /// indicates that something special is currently happening to this point
+  unsigned int review_flag;
+
+  /// returns the distance between two of these objects
+  double distance2(const Point & other) const {
+    return coord.distance2(other.coord);
+  };
+
+  /// creates a shuffle for us with a given shift
+  //void set_shuffle(Shuffle & shuffle);
+};
+
+
+//----------------------------------------------------------------------
+/// returns true if floor(ln_base2(x)) < floor(ln_base2(y)), using
+/// Chan's neat trick...
+inline bool floor_ln2_less(unsigned x, unsigned y) {
+  if (x>y) return false;
+  return (x < (x^y)); // beware of operator precedence...
+}
+
+
+//----------------------------------------------------------------------
+/// returns the ID for the specified point...
+inline int ClosestPair2D::_ID(const Point * point) const {
+  return point - &(_points[0]);
+}
+
+
+//
+inline unsigned int ClosestPair2D::size() {
+  return _points.size() - _available_points.size();
+}
+
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLOSESTPAIR2D__HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/ClosestPair2DBase.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/ClosestPair2DBase.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/ClosestPair2DBase.hh	(revision 11)
@@ -0,0 +1,129 @@
+//STARTHEADER
+// $Id: ClosestPair2DBase.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_CLOSESTPAIR2DBASE__HH__
+#define __FASTJET_CLOSESTPAIR2DBASE__HH__
+
+#include<vector>
+#include "Utilities/Fastjet/include/fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+/// class for representing 2d coordinates and carrying out some basic 
+/// operations on them
+class Coord2D {
+public:
+  double x, y;
+
+  Coord2D() {};
+
+  Coord2D(double a, double b): x(a), y(b) {};
+
+  /// return the vector difference between two coordinates
+  Coord2D operator-(const Coord2D & other) const {
+    return Coord2D(x - other.x,  y - other.y);};
+
+  /// return the vector sum between two coordinates
+  Coord2D operator+(const Coord2D & other) const {
+    return Coord2D(x + other.x,  y + other.y);};
+
+  /// return the product of the coordinate with the factor
+  Coord2D operator*(double factor) const {return Coord2D(factor*x,factor*y);};
+  friend Coord2D operator*(double factor, const Coord2D & coord) {
+    return Coord2D(factor*coord.x,factor*coord.y);
+  }
+
+  /// division of each component of coordinate
+  Coord2D operator/(double divisor) const {
+    return Coord2D(x / divisor,  y / divisor);};
+
+  /// return the squared distance between two coordinates
+  friend double distance2(const Coord2D & a, const Coord2D & b) {
+    double dx = a.x - b.x, dy = a.y-b.y;
+    return dx*dx+dy*dy;
+  };
+  /// return the squared distance between two coordinates
+  double distance2(const Coord2D & b) const {
+    double dx = x - b.x, dy = y-b.y;
+    return dx*dx+dy*dy;
+  };
+};
+
+
+//----------------------------------------------------------------------
+/// abstract base class for finding closest pairs in 2D
+class ClosestPair2DBase {
+public:
+  /// provides the IDs of the closest pair as well as the squared
+  /// distance between them
+  virtual void closest_pair(unsigned int & ID1, unsigned int & ID2, 
+			    double & distance2) const = 0;
+  
+  /// removes the entry labelled by ID from the object;
+  virtual void remove(unsigned int ID) = 0;
+ 
+  /// inserts the position into the closest pair structure and returns the
+  /// ID that has been allocated for the object.
+  virtual unsigned int insert(const Coord2D & position) = 0;
+
+  /// replaces the specified ID1 and ID2 with something at a new position
+  /// assuming that ID1 and ID2 are in sequence wrt position; it returns
+  /// the ID of the new object...
+  virtual unsigned int replace(unsigned int ID1, unsigned int ID2, 
+			       const Coord2D & position) {
+    remove(ID1); 
+    remove(ID2); 
+    unsigned new_ID = insert(position);
+    return(new_ID);
+  };
+
+  /// replaces IDs_to_remove with points at the new_positions
+  /// indicating the IDs allocated to the new points in new_IDs
+  virtual void replace_many(const std::vector<unsigned int> & IDs_to_remove,
+		       const std::vector<Coord2D> & new_positions,
+		       std::vector<unsigned int> & new_IDs) {
+    for(unsigned i = 0; i < IDs_to_remove.size(); i++) {
+      remove(IDs_to_remove[i]);}
+    new_IDs.resize(0);
+    for(unsigned i = 0; i < new_positions.size(); i++) {
+      new_IDs.push_back(insert(new_positions[i]));}
+  }
+
+  virtual unsigned int size() = 0;
+
+  virtual ~ClosestPair2DBase() {};
+  
+};
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CLOSESTPAIR2DBASE__HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn2piCylinder.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn2piCylinder.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn2piCylinder.hh	(revision 11)
@@ -0,0 +1,267 @@
+//STARTHEADER
+// $Id: Dnn2piCylinder.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#ifndef __FASTJET_DNN2PICYLINDER_HH__
+#define __FASTJET_DNN2PICYLINDER_HH__
+
+#include "fastjet/internal/DynamicNearestNeighbours.hh"
+#include "fastjet/internal/DnnPlane.hh"
+#include "fastjet/internal/numconsts.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+/// class derived from DynamicNearestNeighbours that provides an
+/// implementation for the surface of cylinder (using one 
+/// DnnPlane object spanning 0--2pi).
+class Dnn2piCylinder : public DynamicNearestNeighbours {
+ public:
+  /// empty initaliser
+  Dnn2piCylinder() {}
+
+  /// Initialiser from a set of points on an Eta-Phi plane, where
+  /// eta can have an arbitrary ranges and phi must be in range
+  /// 0 <= phi < 2pi;
+  /// 
+  /// NB: this class is more efficient than the plain Dnn4piCylinder
+  /// class, but can give wrong answers when the nearest neighbour is
+  /// further away than 2pi (in this case a point's nearest neighbour
+  /// becomes itself, because it is considered to be a distance 2pi
+  /// away). For the kt-algorithm (e.g.) this is actually not a
+  /// problem (the distance need only be accurate when it is less than
+  /// R), so we can tell the routine to ignore this problem --
+  /// alternatively the routine will crash if it detects it occurring
+  /// (only when finding the nearest neighbour index, not its
+  /// distance).
+  Dnn2piCylinder(const std::vector<EtaPhi> &,
+		 const bool & ignore_nearest_is_mirror = false,
+		 const bool & verbose = false );
+
+  /// Returns the index of  the nearest neighbour of point labelled
+  /// by ii (assumes ii is valid)
+  int NearestNeighbourIndex(const int & ii) const ;
+
+  /// Returns the distance to the nearest neighbour of point labelled
+  /// by index ii (assumes ii is valid)
+  double NearestNeighbourDistance(const int & ii) const ;
+
+  /// Returns true iff the given index corresponds to a point that
+  /// exists in the DNN structure (meaning that it has been added, and
+  /// not removed in the meantime)
+  bool Valid(const int & index) const;
+
+  void RemoveAndAddPoints(const std::vector<int> & indices_to_remove,
+			  const std::vector<EtaPhi> & points_to_add,
+			  std::vector<int> & indices_added,
+			  std::vector<int> & indices_of_updated_neighbours);
+
+  ~Dnn2piCylinder();
+
+ private:
+
+  // our extras to help us navigate, find distance, etc.
+  const static int INEXISTENT_VERTEX=-3;
+
+  bool _verbose;
+
+  bool _ignore_nearest_is_mirror;
+
+  /// Picture of how things will work... Copy 0--pi part of the 0--2pi
+  /// cylinder into a region 2pi--2pi+ a bit of a Euclidean plane. Below we
+  /// show points labelled by + that have a mirror image in this
+  /// manner, while points labelled by * do not have a mirror image.
+  ///      	 			  
+  ///      |           .     |		  
+  ///      |	       .     |		  
+  ///      |           .     |		  
+  ///      |           .     |		  
+  ///      |        2  .     |		  
+  ///      |        *  .     |		  
+  ///      | +         . +   |		  
+  ///      | 0         . 1   |
+  ///      |	       .     |
+  ///      0          2pi   2pi + a bit
+  ///   	     
+  /// Each "true" point has its true "cylinder" index (the index that
+  /// is known externally to this class) as well as euclidean plane
+  /// indices (main_index and mirror index in the MirrorVertexInfo
+  /// structure), which are private concepts of this class.
+  /// 
+  /// In above picture our structures would hold the following info
+  /// (the picture shows the euclidean-plane numbering)
+  ///
+  /// _mirror_info[cylinder_index = 0] = (0, 1)
+  /// _mirror_info[cylinder_index = 1] = (2, INEXISTENT_VERTEX)
+  ///
+  /// We also need to be able to go from the euclidean plane indices
+  /// back to the "true" cylinder index, and for this purpose we use
+  /// the std::vector _cylinder_index_of_plane_vertex[...], which in the above example has
+  /// the following contents
+  ///
+  /// _cylinder_index_of_plane_vertex[0] = 0
+  /// _cylinder_index_of_plane_vertex[1] = 0
+  /// _cylinder_index_of_plane_vertex[2] = 1
+  ///
+
+  /// 
+  struct MirrorVertexInfo {
+    /// index of the given point (appearing in the range 0--2pi) in the 
+    /// 0--2pi euclidean plane structure (position will coincide with
+    /// that on the 0--2pi cylinder, but index labelling it will be
+    /// different)
+    int main_index; 
+    /// index of the mirror point (appearing in the range 2pi--3pi) in the
+    /// 0--3pi euclidean plane structure
+    int mirror_index; 
+  };
+
+  // for each "true" vertex we have reference to indices in the euclidean
+  // plane structure
+  std::vector<MirrorVertexInfo> _mirror_info;
+  // for each index in the euclidean 0--2pi plane structure we want to
+  // be able to get back to the "true" vertex index on the overall
+  // 0--2pi cylinder structure
+  std::vector<int> _cylinder_index_of_plane_vertex;
+
+  // NB: we define POINTERS here because the initialisation gave
+  //     us problems (things crashed!), perhaps because in practice
+  //     we were making a copy without being careful and defining
+  //     a proper copy constructor.
+  DnnPlane * _DNN;
+
+  /// given a phi value in the 0--pi range return one 
+  /// in the 2pi--3pi range; whereas if it is in the pi-2pi range then
+  /// remap it to be inthe range (-pi)--0.
+  inline EtaPhi _remap_phi(const EtaPhi & point) {
+    double phi = point.second;
+    if (phi < pi) { phi += twopi ;} else {phi -= twopi;}
+    return EtaPhi(point.first, phi);}
+
+
+  //----------------------------------------------------------------------
+  /// Actions here are similar to those in the
+  /// Dnn3piCylinder::_RegisterCylinderPoint case, however here we do
+  /// NOT create the mirror point -- instead we initialise the structure
+  /// as if there were no need for the mirror point.
+  ///
+  /// ADDITIONALLY push the cylinder_point onto the vector plane_points.
+  void _RegisterCylinderPoint (const EtaPhi & cylinder_point,
+			       std::vector<EtaPhi> & plane_points);
+
+  /// For each plane point specified in the vector plane_indices,
+  /// establish whether there is a need to create a mirror point
+  /// according to the following criteria:
+  ///
+  /// . phi < pi
+  /// . mirror does not already exist
+  /// . phi < NearestNeighbourDistance 
+  ///   (if this is not true then there is no way that its mirror point
+  ///   could have a nearer neighbour).
+  ///
+  /// If conditions all hold, then create the mirror point, insert it
+  /// into the _DNN structure, adjusting any nearest neighbours, and
+  /// return the list of plane points whose nearest neighbours have
+  /// changed (this will include the new neighbours that have just been
+  /// added)
+  void _CreateNecessaryMirrorPoints(
+			  const std::vector<int> & plane_indices,
+			  std::vector<int> & updated_plane_points);
+
+};
+
+
+// here follow some inline implementations of the simpler of the
+// functions defined above
+
+//----------------------------------------------------------------------
+/// Note: one of the difficulties of the 0--2pi mapping is that
+/// a point may have its mirror copy as its own nearest neighbour
+/// (if no other point is within a distance of 2pi). This does
+/// not matter for the kt_algorithm with
+/// reasonable values of radius, but might matter for a general use
+/// of this algorithm -- depending on whether or not the user has
+/// initialised the class with instructions to ignore this problem the
+/// program will detect and ignore it, or crash.
+inline int Dnn2piCylinder::NearestNeighbourIndex(const int & current) const {
+  int main_index = _mirror_info[current].main_index;
+  int mirror_index = _mirror_info[current].mirror_index;
+  int plane_index;
+  if (mirror_index == INEXISTENT_VERTEX ) {
+    plane_index = _DNN->NearestNeighbourIndex(main_index);
+  } else {
+    plane_index = (
+	_DNN->NearestNeighbourDistance(main_index) < 
+	_DNN->NearestNeighbourDistance(mirror_index)) ? 
+      _DNN->NearestNeighbourIndex(main_index) : 
+      _DNN->NearestNeighbourIndex(mirror_index) ; 
+  }
+  int this_cylinder_index = _cylinder_index_of_plane_vertex[plane_index];
+  // either the user has acknowledged the fact that they may get the
+  // mirror copy as the closest point, or crash if it should occur
+  // that mirror copy is the closest point.
+  assert(_ignore_nearest_is_mirror || this_cylinder_index != current);
+  //if (this_cylinder_index == current) {
+  //  cerr << "WARNING point "<<current<<
+  //    " has its mirror copy as its own nearest neighbour"<<endl;
+  //}
+  return this_cylinder_index;
+}
+
+inline double Dnn2piCylinder::NearestNeighbourDistance(const int & current) const {
+  int main_index = _mirror_info[current].main_index;
+  int mirror_index = _mirror_info[current].mirror_index;
+  if (mirror_index == INEXISTENT_VERTEX ) {
+    return _DNN->NearestNeighbourDistance(main_index);
+  } else {
+    return (
+	_DNN->NearestNeighbourDistance(main_index) < 
+	_DNN->NearestNeighbourDistance(mirror_index)) ? 
+      _DNN->NearestNeighbourDistance(main_index) : 
+      _DNN->NearestNeighbourDistance(mirror_index) ; 
+  }
+ 
+}
+
+inline bool Dnn2piCylinder::Valid(const int & index) const {
+  return (_DNN->Valid(_mirror_info[index].main_index));
+}
+
+
+inline Dnn2piCylinder::~Dnn2piCylinder() {
+  delete _DNN; 
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif //  __FASTJET_DNN2PICYLINDER_HH__
+#endif //DROP_CGAL 
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn3piCylinder.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn3piCylinder.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn3piCylinder.hh	(revision 11)
@@ -0,0 +1,257 @@
+//STARTHEADER
+// $Id: Dnn3piCylinder.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#ifndef __FASTJET_DNN3PICYLINDER_HH__
+#define __FASTJET_DNN3PICYLINDER_HH__
+
+#include "fastjet/internal/DynamicNearestNeighbours.hh"
+#include "fastjet/internal/DnnPlane.hh"
+#include "fastjet/internal/numconsts.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// class derived from DynamicNearestNeighbours that provides an
+/// implementation for the surface of cylinder (using one 
+/// DnnPlane object spanning 0--3pi).
+class Dnn3piCylinder : public DynamicNearestNeighbours {
+ public:
+  /// empty initaliser
+  Dnn3piCylinder() {}
+
+  /// Initialiser from a set of points on an Eta-Phi plane, where
+  /// eta can have an arbitrary ranges and phi must be in range
+  /// 0 <= phi < 2pi;
+  /// 
+  /// NB: this class is more efficient than the plain Dnn4piCylinder
+  /// class, but can give wrong answers when the nearest neighbour is
+  /// further away than 2pi (in this case a point's nearest neighbour
+  /// becomes itself, because it is considered to be a distance 2pi
+  /// away). For the kt-algorithm (e.g.) this is actually not a
+  /// problem (the distance need only be accurate when it is less than
+  /// R), so we can tell the routine to ignore this problem --
+  /// alternatively the routine will crash if it detects it occurring
+  /// (only when finding the nearest neighbour index, not its
+  /// distance).
+  Dnn3piCylinder(const std::vector<EtaPhi> &,
+		 const bool & ignore_nearest_is_mirror = false,
+		 const bool & verbose = false );
+
+  /// Returns the index of  the nearest neighbour of point labelled
+  /// by ii (assumes ii is valid)
+  int NearestNeighbourIndex(const int & ii) const ;
+
+  /// Returns the distance to the nearest neighbour of point labelled
+  /// by index ii (assumes ii is valid)
+  double NearestNeighbourDistance(const int & ii) const ;
+
+  /// Returns true iff the given index corresponds to a point that
+  /// exists in the DNN structure (meaning that it has been added, and
+  /// not removed in the meantime)
+  bool Valid(const int & index) const;
+
+  void RemoveAndAddPoints(const std::vector<int> & indices_to_remove,
+			  const std::vector<EtaPhi> & points_to_add,
+			  std::vector<int> & indices_added,
+			  std::vector<int> & indices_of_updated_neighbours);
+
+  ~Dnn3piCylinder();
+
+ private:
+
+  // our extras to help us navigate, find distance, etc.
+  const static int INEXISTENT_VERTEX=-3;
+
+  bool _verbose;
+
+  bool _ignore_nearest_is_mirror;
+
+  /// Picture of how things will work... Copy 0--pi part of the 0--2pi
+  /// cylinder into a region 2pi--3pi of a Euclidean plane. Below we
+  /// show points labelled by + that have a mirror image in this
+  /// manner, while points labelled by * do not have a mirror image.
+  ///      	 			  
+  ///      |           .     |		  
+  ///      |	       .     |		  
+  ///      |           .     |		  
+  ///      |           .     |		  
+  ///      |        2  .     |		  
+  ///      |        *  .     |		  
+  ///      | +         . +   |		  
+  ///      | 0         . 1   |
+  ///      |	       .     |
+  ///      0          2pi   3pi
+  ///   	     
+  /// Each "true" point has its true "cylinder" index (the index that
+  /// is known externally to this class) as well as euclidean plane
+  /// indices (main_index and mirror index in the MirrorVertexInfo
+  /// structure), which are private concepts of this class.
+  /// 
+  /// In above picture our structures would hold the following info
+  /// (the picture shows the euclidean-plane numbering)
+  ///
+  /// _mirror_info[cylinder_index = 0] = (0, 1)
+  /// _mirror_info[cylinder_index = 1] = (2, INEXISTENT_VERTEX)
+  ///
+  /// We also need to be able to go from the euclidean plane indices
+  /// back to the "true" cylinder index, and for this purpose we use
+  /// the vector _cylinder_index_of_plane_vertex[...], which in the above example has
+  /// the following contents
+  ///
+  /// _cylinder_index_of_plane_vertex[0] = 0
+  /// _cylinder_index_of_plane_vertex[1] = 0
+  /// _cylinder_index_of_plane_vertex[2] = 1
+  ///
+
+  /// 
+  struct MirrorVertexInfo {
+    /// index of the given point (appearing in the range 0--2pi) in the 
+    /// 0--3pi euclidean plane structure (position will coincide with
+    /// that on the 0--2pi cylinder, but index labelling it will be
+    /// different)
+    int main_index; 
+    /// index of the mirror point (appearing in the range 2pi--3pi) in the
+    /// 0--3pi euclidean plane structure
+    int mirror_index; 
+  };
+
+  // for each "true" vertex we have reference to indices in the euclidean
+  // plane structure
+  std::vector<MirrorVertexInfo> _mirror_info;
+  // for each index in the euclidean 0--3pi plane structure we want to
+  // be able to get back to the "true" vertex index on the overall
+  // 0--2pi cylinder structure
+  std::vector<int> _cylinder_index_of_plane_vertex;
+
+  // NB: we define POINTERS here because the initialisation gave
+  //     us problems (things crashed!), perhaps because in practice
+  //     we were making a copy without being careful and defining
+  //     a proper copy constructor.
+  DnnPlane * _DNN;
+
+  /// given a phi value in the 0--2pi range return one 
+  /// in the pi--3pi range.
+  inline EtaPhi _remap_phi(const EtaPhi & point) {
+    double phi = point.second;
+    if (phi < pi) { phi += twopi ;}
+    return EtaPhi(point.first, phi);}
+
+
+  //----------------------------------------------------------------------
+  /// What on earth does this do?
+  ///
+  /// Example: last true "cylinder" index was 15
+  ///          last plane index was 23
+  /// 
+  /// Then: _cylinder_index_of_plane_vertex.size() = 24 and 
+  ///       _mirror_info.size() = 16
+  ///
+  /// IF cylinder_point's phi < pi then
+  ///   create:  _mirror_info[16] = (main_index = 24, mirror_index=25) 
+  ///            _cylinder_index_of_plane_vertex[24] = 16
+  ///            _cylinder_index_of_plane_vertex[25] = 16
+  /// ELSE
+  ///  create: _mirror_info[16] = (main_index = 24, mirror_index=INEXISTENT..) 
+  ///          _cylinder_index_of_plane_vertex[24] = 16
+  ///
+  /// ADDITIONALLY push the cylinder_point (and if it exists the mirror
+  /// copy) onto the vector plane_points.
+  void _RegisterCylinderPoint (const EtaPhi & cylinder_point,
+			       std::vector<EtaPhi> & plane_points);
+};
+
+
+// here follow some inline implementations of the simpler of the
+// functions defined above
+
+//----------------------------------------------------------------------
+/// Note: one of the difficulties of the 0--3pi mapping is that
+/// a point may have its mirror copy as its own nearest neighbour
+/// (if no other point is within a distance of 2pi). This does
+/// not matter for the kt_algorithm with
+/// reasonable values of radius, but might matter for a general use
+/// of this algorithm -- depending on whether or not the user has
+/// initialised the class with instructions to ignore this problem the
+/// program will detect and ignore it, or crash.
+inline int Dnn3piCylinder::NearestNeighbourIndex(const int & current) const {
+  int main_index = _mirror_info[current].main_index;
+  int mirror_index = _mirror_info[current].mirror_index;
+  int plane_index;
+  if (mirror_index == INEXISTENT_VERTEX ) {
+    plane_index = _DNN->NearestNeighbourIndex(main_index);
+  } else {
+    plane_index = (
+	_DNN->NearestNeighbourDistance(main_index) < 
+	_DNN->NearestNeighbourDistance(mirror_index)) ? 
+      _DNN->NearestNeighbourIndex(main_index) : 
+      _DNN->NearestNeighbourIndex(mirror_index) ; 
+  }
+  int this_cylinder_index = _cylinder_index_of_plane_vertex[plane_index];
+  // either the user has acknowledged the fact that they may get the
+  // mirror copy as the closest point, or crash if it should occur
+  // that mirror copy is the closest point.
+  assert(_ignore_nearest_is_mirror || this_cylinder_index != current);
+  //if (this_cylinder_index == current) {
+  //  std::cerr << "WARNING point "<<current<<
+  //    " has its mirror copy as its own nearest neighbour"<<endl;
+  //}
+  return this_cylinder_index;
+}
+
+inline double Dnn3piCylinder::NearestNeighbourDistance(const int & current) const {
+  int main_index = _mirror_info[current].main_index;
+  int mirror_index = _mirror_info[current].mirror_index;
+  if (mirror_index == INEXISTENT_VERTEX ) {
+    return _DNN->NearestNeighbourDistance(main_index);
+  } else {
+    return (
+	_DNN->NearestNeighbourDistance(main_index) < 
+	_DNN->NearestNeighbourDistance(mirror_index)) ? 
+      _DNN->NearestNeighbourDistance(main_index) : 
+      _DNN->NearestNeighbourDistance(mirror_index) ; 
+  }
+ 
+}
+
+inline bool Dnn3piCylinder::Valid(const int & index) const {
+  return (_DNN->Valid(_mirror_info[index].main_index));
+}
+
+
+inline Dnn3piCylinder::~Dnn3piCylinder() {
+  delete _DNN; 
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif //  __FASTJET_DNN3PICYLINDER_HH__
+#endif //  DROP_CGAL 
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn4piCylinder.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn4piCylinder.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/Dnn4piCylinder.hh	(revision 11)
@@ -0,0 +1,126 @@
+//STARTHEADER
+// $Id: Dnn4piCylinder.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#ifndef __FASTJET_DNN4PICYLINDER_HH__
+#define __FASTJET_DNN4PICYLINDER_HH__
+
+#include "fastjet/internal/DynamicNearestNeighbours.hh"
+#include "fastjet/internal/DnnPlane.hh"
+#include "fastjet/internal/numconsts.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// class derived from DynamicNearestNeighbours that provides an
+/// implementation for the surface of cylinder (using two copies of
+/// DnnPlane, one running from 0--2pi, the other from pi--3pi).
+class Dnn4piCylinder : public DynamicNearestNeighbours {
+ public:
+  /// empty initaliser
+  Dnn4piCylinder() {}
+
+  /// Initialiser from a set of points on an Eta-Phi plane, where
+  /// eta can have an arbitrary ranges and phi must be in range
+  /// 0 <= phi < 2pi
+  Dnn4piCylinder(const std::vector<EtaPhi> &, const bool & verbose = false );
+
+  /// Returns the index of  the nearest neighbour of point labelled
+  /// by ii (assumes ii is valid)
+  int NearestNeighbourIndex(const int & ii) const ;
+
+  /// Returns the distance to the nearest neighbour of point labelled
+  /// by index ii (assumes ii is valid)
+  double NearestNeighbourDistance(const int & ii) const ;
+
+  /// Returns true iff the given index corresponds to a point that
+  /// exists in the DNN structure (meaning that it has been added, and
+  /// not removed in the meantime)
+  bool Valid(const int & index) const;
+
+  void RemoveAndAddPoints(const std::vector<int> & indices_to_remove,
+			  const std::vector<EtaPhi> & points_to_add,
+			  std::vector<int> & indices_added,
+			  std::vector<int> & indices_of_updated_neighbours);
+
+  ~Dnn4piCylinder();
+
+ private:
+
+  bool _verbose;
+
+  // NB: we define POINTERS here because the initialisation gave
+  //     us problems (things crashed!), perhaps because in practice
+  //     we were making a copy without being careful and defining
+  //     a proper copy constructor.
+  DnnPlane * _DNN1, * _DNN2;
+
+  /// given a phi value in the 0--2pi range return one 
+  /// in the pi--3pi range.
+  inline EtaPhi _remap_phi(const EtaPhi & point) {
+    double phi = point.second;
+    if (phi < pi) { phi += twopi ;}
+    return EtaPhi(point.first, phi);}
+
+};
+
+
+// here follow some inline implementations of the simpler of the
+// functions defined above
+
+inline int Dnn4piCylinder::NearestNeighbourIndex(const int & current) const {
+  return (_DNN1->NearestNeighbourDistance(current) < 
+	  _DNN2->NearestNeighbourDistance(current)) ? 
+    _DNN1->NearestNeighbourIndex(current) : 
+    _DNN2->NearestNeighbourIndex(current) ; 
+}
+
+inline double Dnn4piCylinder::NearestNeighbourDistance(const int & current) const {
+  return (_DNN1->NearestNeighbourDistance(current) < 
+	  _DNN2->NearestNeighbourDistance(current)) ? 
+    _DNN1->NearestNeighbourDistance(current) : 
+    _DNN2->NearestNeighbourDistance(current) ; 
+}
+
+inline bool Dnn4piCylinder::Valid(const int & index) const {
+  return (_DNN1->Valid(index) && _DNN2->Valid(index));
+}
+
+
+inline Dnn4piCylinder::~Dnn4piCylinder() {
+  delete _DNN1; 
+  delete _DNN2;
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif //  __FASTJET_DNN4PICYLINDER_HH__
+#endif //  DROP_CGAL 
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/DnnPlane.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/DnnPlane.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/DnnPlane.hh	(revision 11)
@@ -0,0 +1,163 @@
+//STARTHEADER
+// $Id: DnnPlane.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+
+#ifndef __FASTJET_DNNPLANE_HH__
+#define __FASTJET_DNNPLANE_HH__
+
+#include "fastjet/internal/Triangulation.hh"
+#include "fastjet/internal/DynamicNearestNeighbours.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+/// class derived from DynamicNearestNeighbours that provides an
+/// implementation for the Euclidean plane
+class DnnPlane : public DynamicNearestNeighbours {
+ public:
+  /// empty initaliser
+  DnnPlane() {}
+
+  /// Initialiser from a set of points on an Eta-Phi plane, where both
+  /// eta and phi can have arbitrary ranges
+  DnnPlane(const std::vector<EtaPhi> &, const bool & verbose = false );
+
+
+  /// Returns the index of  the nearest neighbour of point labelled
+  /// by ii (assumes ii is valid)
+  int NearestNeighbourIndex(const int & ii) const ;
+
+  /// Returns the distance to the nearest neighbour of point labelled
+  /// by index ii (assumes ii is valid)
+  double NearestNeighbourDistance(const int & ii) const ;
+
+  /// Returns true iff the given index corresponds to a point that
+  /// exists in the DNN structure (meaning that it has been added, and
+  /// not removed in the meantime)
+  bool Valid(const int & index) const;
+
+  void RemoveAndAddPoints(const std::vector<int> & indices_to_remove,
+			  const std::vector<EtaPhi> & points_to_add,
+			  std::vector<int> & indices_added,
+			  std::vector<int> & indices_of_updated_neighbours);
+
+  /// returns the EtaPhi of point with index i.
+  EtaPhi etaphi(const int i) const;
+  /// returns the eta point with index i.
+  double eta(const int i) const;
+  /// returns the phi point with index i.
+  double phi(const int i) const;
+
+ private:
+
+  /// Structure containing a vertex_handle and cached information on
+  /// the nearest neighbour.
+  struct SuperVertex {
+    Vertex_handle vertex; // NULL indicates inexistence...
+    double NNdistance;
+    int NNindex;
+    // later on for cylinder put a second vertex?
+  };
+
+  std::vector<SuperVertex> _supervertex;
+  //set<Vertex_handle> _vertex_set;
+  bool _verbose;
+
+  static const bool _crash_on_coincidence = true;
+  //static const bool _crash_on_coincidence = false;
+
+  Triangulation _TR; /// CGAL object for dealing with triangulations
+
+  /// calculates and returns the euclidean distance between points p1
+  /// and p2
+  inline double _euclid_distance(const Point& p1, const Point& p2) const {
+    double distx= p1.x()-p2.x();
+    double disty= p1.y()-p2.y();
+    return distx*distx+disty*disty;
+  }
+
+  //---------------------------------------------------------------------- 
+  /// Determines the index and distance of the nearest neighbour to 
+  /// point j and puts the information into the _supervertex entry for j
+  void _SetNearest(const int & j);
+
+  //----------------------------------------------------------------------
+  /// Determines and stores the nearest neighbour of j.
+  ///
+  /// For each voronoi neighbour D of j if the distance between j and D
+  /// is less than D's own nearest neighbour, then update the
+  /// nearest-neighbour info in D; push D's index onto 
+  /// indices_of_updated_neighbours
+  ///
+  /// Note that j is NOT pushed onto indices_of_updated_neighbours --
+  /// if you want it there, put it there yourself.
+  void _SetAndUpdateNearest(const int & j, 
+			    std::vector<int> & indices_of_updated_neighbours);
+
+  /// given a vertex_handle returned by CGAL on insertion of a new
+  /// points, crash if it turns out that it corresponds to a vertex
+  /// that we already knew about (usually because two points coincide)
+  void _CrashIfVertexPresent(const Vertex_handle & vertex, 
+			     const int & its_index);
+
+};
+
+
+// here follow some inline implementations of the simpler of the
+// functions defined above
+
+inline int DnnPlane::NearestNeighbourIndex(const int & ii) const {
+  return _supervertex[ii].NNindex;}
+
+inline double DnnPlane::NearestNeighbourDistance(const int & ii) const {
+  return _supervertex[ii].NNdistance;}
+
+inline bool DnnPlane::Valid(const int & index) const {
+  if (index >= 0 && index < static_cast<int>(_supervertex.size())) {
+    return (_supervertex[index].vertex != NULL);} else {return false;} }
+
+inline EtaPhi DnnPlane::etaphi(const int i) const {
+  Point * p = & (_supervertex[i].vertex->point());
+  return EtaPhi(p->x(),p->y()); }
+
+inline double DnnPlane::eta(const int i) const {
+  return _supervertex[i].vertex->point().x(); }
+
+inline double DnnPlane::phi(const int i) const {
+  return _supervertex[i].vertex->point().y(); }
+
+
+FASTJET_END_NAMESPACE
+
+#endif //  __FASTJET_DNNPLANE_HH__
+
+#endif // DROP_CGAL
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/DynamicNearestNeighbours.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/DynamicNearestNeighbours.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/DynamicNearestNeighbours.hh	(revision 11)
@@ -0,0 +1,171 @@
+//STARTHEADER
+// $Id: DynamicNearestNeighbours.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_DYNAMICNEARESTNEIGHBOURS_HH__
+#define __FASTJET_DYNAMICNEARESTNEIGHBOURS_HH__
+
+#include<vector>
+#include<string>
+#include<iostream>
+#include<sstream>
+#include<cassert>
+#include "Utilities/Fastjet/include/fastjet/internal/numconsts.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// Shortcut for dealing with eta-phi coordinates.
+//typedef std::pair<double,double> EtaPhi;
+
+/// use a class instead of a pair so that phi can be sanitized
+/// and put into proper range on initialization.
+class EtaPhi {
+public:
+  double first, second;
+  EtaPhi() {}
+  EtaPhi(double a, double b) {first = a; second = b;}
+  /// put things into the desired range.
+  void sanitize() {    
+    if (second <  0)     second += twopi; 
+    if (second >= twopi) second -= twopi;
+  }
+
+};
+
+/// class corresponding to errors that will be thrown by Dynamic
+/// Nearest Neighbours code
+class DnnError {
+public:
+  // constructors
+  DnnError() {;};
+  DnnError(const std::string & message) {
+    _message = message; std::cerr << message << std::endl;};
+
+  std::string message() const {return _message;};
+
+private:
+  std::string _message;
+};
+
+
+///
+/// Abstract base class for quick location of nearest neighbours in a set of
+/// points, with facilities for adding and removing points from the
+/// set after initialisation. Derived classes will be
+/// named according to the convention DnnSomeName (e.g. DnnPlane).
+///
+/// The main purpose of this abstract base class is to define the
+/// general interface of a whole set of classes that deal with
+/// nearest-neighbour location on different 2-d geometries and with
+/// various underlying data structures and algorithms.
+///
+class DynamicNearestNeighbours {
+
+public:
+  /// Dummy initialiser --- does nothing!
+  //virtual DynamicNearestNeighbours() {};
+   
+  /// Initialiser --- sets up the necessary structures to allow efficient
+  /// nearest-neighbour finding on the std::vector<EtaPhi> of input points
+  //virtual DynamicNearestNeighbours(const std::vector<EtaPhi> &, 
+  //				   const bool & verbose = false ) = 0;
+
+  /// Returns the index of the nearest neighbour of point labelled
+  /// by ii (assumes ii is valid)
+  virtual int NearestNeighbourIndex(const int & ii) const = 0;
+
+  /// Returns the distance to the nearest neighbour of point labelled
+  /// by index ii (assumes ii is valid)
+  virtual double NearestNeighbourDistance(const int & ii) const = 0;
+
+  /// Returns true iff the given index corresponds to a point that
+  /// exists in the DNN structure (meaning that it has been added, and
+  /// not removed in the meantime)
+  virtual bool Valid(const int & index) const = 0;
+
+  /// remove the points labelled by the std::vector indices_to_remove, and
+  /// add the points specified by the std::vector points_to_add
+  /// (corresponding indices will be calculated automatically); the
+  /// idea behind this routine is that the points to be added will
+  /// somehow be close to the one or other of the points being removed
+  /// and this can be used by the implementation to provide hints for
+  /// inserting the new points in whatever structure it is using.  In a
+  /// kt-algorithm the points being added will be a result of a
+  /// combination of the points to be removed -- hence the proximity
+  /// is (more or less) guaranteed.
+  virtual void RemoveAndAddPoints(const std::vector<int> & indices_to_remove,
+			  const std::vector<EtaPhi> & points_to_add,
+			  std::vector<int> & indices_added,
+			  std::vector<int> & indices_of_updated_neighbours) = 0;
+
+
+  /// Remove the point labelled by index and return the list of
+  /// points whose nearest neighbours have changed in the process
+  inline void RemovePoint (const int & index,
+			   std::vector<int> & indices_of_updated_neighbours) {
+    std::vector<int> indices_added;
+    std::vector<EtaPhi> points_to_add;
+    std::vector<int> indices_to_remove(1);
+    indices_to_remove[0] = index;
+    RemoveAndAddPoints(indices_to_remove, points_to_add, indices_added,
+		       indices_of_updated_neighbours
+		       );};
+
+
+  /// Removes the two points labelled by index1, index2 and adds in the
+  /// a point with coordinates newpoint; it returns an index for the new 
+  /// point (index 3) and a std::vector of indices of neighbours whose
+  /// nearest neighbour has changed (the list includes index3, i.e. the new
+  /// point).
+  inline void RemoveCombinedAddCombination(
+			const int & index1, const int & index2,
+			const EtaPhi & newpoint,
+			int & index3,
+			std::vector<int> & indices_of_updated_neighbours) {
+    std::vector<int> indices_added(1);
+    std::vector<EtaPhi> points_to_add(1);
+    std::vector<int> indices_to_remove(2);
+    indices_to_remove[0] = index1;
+    indices_to_remove[1] = index2;
+    points_to_add[0] = newpoint;
+    RemoveAndAddPoints(indices_to_remove, points_to_add, indices_added,
+		       indices_of_updated_neighbours
+		       );
+    index3 = indices_added[0];
+  };
+
+  /// destructor -- here it is now implemented
+  virtual ~DynamicNearestNeighbours () {}
+};
+  
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_DYNAMICNEARESTNEIGHBOURS_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/LimitedWarning.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/LimitedWarning.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/LimitedWarning.hh	(revision 11)
@@ -0,0 +1,66 @@
+//STARTHEADER
+// $Id: LimitedWarning.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_LIMITEDWARNING_HH__
+#define __FASTJET_LIMITEDWARNING_HH__
+
+#include<iostream>
+#include<string>
+
+/// class to provide facilities for giving warnings up to some maximum
+/// number of times
+class LimitedWarning {
+public:
+  
+  /// constructor that provides a default maximum number of warnings
+  LimitedWarning() : _max_warn(_max_warn_default), _n_warn_so_far(0) {}
+
+  /// constructor that provides a used-set max number of warnings
+  LimitedWarning(int max_warn) : _max_warn(max_warn), _n_warn_so_far(0) {}
+
+  /// output a warning to ostr
+  void warn(const std::string & warning, std::ostream & ostr = std::cerr) {
+    if (_n_warn_so_far < _max_warn) {
+      ostr << "WARNING: ";
+      ostr << warning;
+      _n_warn_so_far++;
+      if (_n_warn_so_far == _max_warn) ostr << " (LAST SUCH WARNING)";
+      ostr << std::endl;
+    }
+  }
+
+private:
+  int _max_warn, _n_warn_so_far;
+  static const int _max_warn_default = 5;
+  
+};
+
+#endif // __FASTJET_LIMITEDWARNING_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/MinHeap.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/MinHeap.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/MinHeap.hh	(revision 11)
@@ -0,0 +1,90 @@
+//STARTHEADER
+// $Id: MinHeap.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_MINHEAP__HH__
+#define __FASTJET_MINHEAP__HH__
+
+#include<vector>
+#include<cassert>
+#include<memory>
+#include<limits>
+#include "Utilities/Fastjet/include/fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//======================================================================
+/// A class which provides a "heap"-like structure that allows
+/// access to a the minimal value of a dynamically changing set of numbers
+class MinHeap {
+public:
+  /// construct a MinHeap from the vector of values, allowing future
+  /// expansion to a maximum size max_size;
+  MinHeap (const std::vector<double> & values, unsigned int max_size) :
+    _heap(max_size) {_initialise(values);};
+
+  /// constructor in which the the maximum size is the size of the values array
+  MinHeap (const std::vector<double> & values) :
+    _heap(values.size()) {_initialise(values);};
+  
+  /// return the location of the minimal value on the heap
+  inline unsigned int minloc() const {
+    return (_heap[0].minloc) - &(_heap[0]);};
+  
+  /// return the minimal value on the heap
+  inline double       minval() const {return _heap[0].minloc->value;};
+
+  inline double operator[](int i) const {return _heap[i].value;};
+
+  /// remove the value at the specified location (i.e. replace it with
+  /// the largest possible value).
+  void remove(unsigned int loc) {
+    update(loc,std::numeric_limits<double>::max());};
+
+  /// update the value at the specified location
+  void update(unsigned int, double);
+
+private:
+
+  struct ValueLoc{
+    double value;
+    ValueLoc * minloc;
+  };
+      
+  std::vector<ValueLoc> _heap;
+
+  void _initialise(const std::vector<double> & values);
+
+
+};
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_MINHEAP__HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/SearchTree.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/SearchTree.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/SearchTree.hh	(revision 11)
@@ -0,0 +1,751 @@
+//STARTHEADER
+// $Id: SearchTree.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef __FASTJET_SEARCHTREE_HH__
+#define __FASTJET_SEARCHTREE_HH__
+
+#include<vector>
+#include<cassert>
+#include<cstddef>
+#include "Utilities/Fastjet/include/fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+//======================================================================
+/// This is the class for a search tree designed to be especially efficient
+/// when looking for successors and predecessors (to be used in Chan's
+/// CP algorithm). It has the requirement that the maximum size of the
+/// search tree must be known in advance.
+template<class T> class SearchTree {
+public:
+
+  class Node;
+  class circulator;
+  class const_circulator;
+
+  /// constructor for a search tree from an ordered vector
+  SearchTree(const std::vector<T> & init);
+
+  /// constructor for a search tree from an ordered vector allowing
+  /// for future growth beyond the current size, up to max_size
+  SearchTree(const std::vector<T> & init, unsigned int max_size);
+
+  /// remove the node corresponding to node_index from the search tree
+  void remove(unsigned node_index);
+  void remove(typename SearchTree::Node * node);
+  void remove(typename SearchTree::circulator & circ);
+
+  /// insert the supplied value into the tree and return a pointer to
+  /// the relevant SearchTreeNode.
+  //Node * insert(const T & value);
+  circulator insert(const T & value);
+
+  const Node & operator[](int i) const {return _nodes[i];};
+
+  /// return the number of elements currently in the search tree
+  unsigned int size() const {return _nodes.size() - _available_nodes.size();}
+
+  /// check that the structure we've obtained makes sense...
+  void verify_structure();
+  void verify_structure_linear() const;
+  void verify_structure_recursive(const Node * , const Node * , const Node * ) const;
+
+  /// print out all elements...
+  void print_elements();
+
+  // tracking the depth may have some speed overhead -- so leave it 
+  // out for the time being...
+#ifdef TRACK_DEPTH
+  /// the max depth the tree has ever reached
+  inline unsigned int max_depth() const {return _max_depth;};
+#else
+  inline unsigned int max_depth() const {return 0;};
+#endif
+
+  int loc(const Node * node) const ;
+
+  /// return predecessor by walking through the tree
+  Node * _find_predecessor(const Node *);
+  /// return successor by walking through the tree
+  Node * _find_successor(const Node *);
+
+  const Node & operator[](unsigned int i) const {return _nodes[i];};
+
+  /// return a circulator to some place in the tree (with a circulator
+  /// you don't care where...)
+  const_circulator somewhere() const;
+  circulator somewhere();
+
+private:
+  
+  void _initialize(const std::vector<T> & init);
+
+  std::vector<Node> _nodes;
+  std::vector<Node *> _available_nodes;
+  Node * _top_node;
+  unsigned int _n_removes;
+
+  
+  /// recursive routine for doing the initial connections assuming things
+  /// are ordered. Assumes this_one's parent is labelled, and was
+  /// generated at a scale "scale" -- connections will be carried out
+  /// including left edge and excluding right edge
+  void _do_initial_connections(unsigned int this_one, unsigned int scale,
+			       unsigned int left_edge, unsigned int right_edge,
+			       unsigned int depth);
+
+  
+#ifdef TRACK_DEPTH
+  unsigned int _max_depth;
+#endif
+
+};
+
+
+//======================================================================
+template<class T> class SearchTree<T>::Node{
+public:
+  Node() {}; /// default constructor
+  
+  
+  /// returns tree if all the tree-related links are set to null for this node
+  bool treelinks_null() const {
+    return ((parent==0) && (left==0) && (right==0));};
+  
+  /// set all the tree-related links are set to null for this node
+  inline void nullify_treelinks() {
+    parent = NULL; 
+    left   = NULL; 
+    right  = NULL;
+  };
+  
+  /// if my parent exists, determine whether I am it's left or right
+  /// node and set the relevant link equal to XX.
+  void reset_parents_link_to_me(Node * XX);
+  
+  T      value;
+  Node * left;
+  Node * right;
+  Node * parent;
+  Node * successor;
+  Node * predecessor;
+};
+
+//----------------------------------------------------------------------
+template<class T> void SearchTree<T>::Node::reset_parents_link_to_me(typename SearchTree<T>::Node * XX) {
+  if (parent == NULL) {return;}
+  if (parent->right == this) {parent->right = XX;}
+  else {parent->left = XX;}
+}
+
+
+
+//======================================================================
+template<class T> class SearchTree<T>::circulator{
+public:
+
+  // so that it can access out _node object;
+  friend class SearchTree<T>::const_circulator;
+  friend class SearchTree<T>;
+
+  circulator() : _node(NULL) {}
+
+  circulator(Node * node) : _node(node) {}
+
+  const T * operator->() const {return &(_node->value);}
+  T * operator->() {return &(_node->value);}
+  const T & operator*() const {return _node->value;}
+  T & operator*() {return _node->value;}
+
+  /// prefix increment (structure copied from stl_bvector.h)
+  circulator & operator++() {
+    _node = _node->successor; 
+    return *this;}
+
+  /// postfix increment ["int" argument tells compiler it's postfix]
+  /// (structure copied from stl_bvector.h)
+  circulator operator++(int) {
+    circulator tmp = *this;
+    _node = _node->successor; 
+    return tmp;}
+
+  /// prefix decrement (structure copied from stl_bvector.h)
+  circulator & operator--() {
+    _node = _node->predecessor; 
+    return *this;}
+
+  /// postfix decrement ["int" argument tells compiler it's postfix]
+  /// (structure copied from stl_bvector.h)
+  circulator operator--(int) {
+    circulator tmp = *this;
+    _node = _node->predecessor; 
+    return tmp;}
+
+  /// return a circulator referring to the next node
+  circulator next() const {
+    return circulator(_node->successor);}
+
+  /// return a circulator referring to the previous node
+  circulator previous() const {
+    return circulator(_node->predecessor);}
+
+  bool operator!=(const circulator & other) const {return other._node != _node;}
+  bool operator==(const circulator & other) const {return other._node == _node;}
+
+private:
+  Node * _node;
+};
+
+
+//======================================================================
+template<class T> class SearchTree<T>::const_circulator{
+public:
+
+  const_circulator() : _node(NULL) {}
+
+  const_circulator(const Node * node) : _node(node) {}
+  const_circulator(const circulator & circ) :_node(circ._node) {}
+
+  const T * operator->() {return &(_node->value);}
+  const T & operator*() const {return _node->value;}
+
+  /// prefix increment (structure copied from stl_bvector.h)
+  const_circulator & operator++() {
+    _node = _node->successor; 
+    return *this;}
+
+  /// postfix increment ["int" argument tells compiler it's postfix]
+  /// (structure copied from stl_bvector.h)
+  const_circulator operator++(int) {
+    const_circulator tmp = *this;
+    _node = _node->successor; 
+    return tmp;}
+
+
+  /// prefix decrement (structure copied from stl_bvector.h)
+  const_circulator & operator--() {
+    _node = _node->predecessor; 
+    return *this;}
+
+  /// postfix decrement ["int" argument tells compiler it's postfix]
+  /// (structure copied from stl_bvector.h)
+  const_circulator operator--(int) {
+    const_circulator tmp = *this;
+    _node = _node->predecessor; 
+    return tmp;}
+
+  /// return a circulator referring to the next node
+  const_circulator next() const {
+    return const_circulator(_node->successor);}
+
+  /// return a circulator referring to the previous node
+  const_circulator previous() const {
+    return const_circulator(_node->predecessor);}
+
+
+
+  bool operator!=(const const_circulator & other) const {return other._node != _node;}
+  bool operator==(const const_circulator & other) const {return other._node == _node;}
+
+private:
+  const Node * _node;
+};
+
+
+
+
+//----------------------------------------------------------------------
+/// initialise from a sorted initial array allowing for a larger
+/// maximum size of the array...
+template<class T> SearchTree<T>::SearchTree(const std::vector<T> & init,
+					    unsigned int max_size) :
+  _nodes(max_size) {
+
+  _available_nodes.reserve(max_size);
+  _available_nodes.resize(max_size - init.size());
+  for (unsigned int i = init.size(); i < max_size; i++) {
+    _available_nodes[i-init.size()] = &(_nodes[i]);
+  }
+
+  _initialize(init);
+}
+
+//----------------------------------------------------------------------
+/// initialise from a sorted initial array
+template<class T> SearchTree<T>::SearchTree(const std::vector<T> & init) :
+  _nodes(init.size()), _available_nodes(0) {
+
+  // reserve space for the list of available nodes
+  _available_nodes.reserve(init.size());
+  _initialize(init);
+}
+
+//----------------------------------------------------------------------
+/// do the actual hard work of initialization
+template<class T> void SearchTree<T>::_initialize(const std::vector<T> & init) {
+
+  _n_removes = 0;
+  unsigned n = init.size();
+  assert(n>=1);
+
+  // reserve space for the list of available nodes
+  //_available_nodes.reserve();
+
+#ifdef TRACK_DEPTH
+  _max_depth     = 0;
+#endif
+
+
+  // validate the input
+  for (unsigned int i = 1; i<n; i++) {
+    assert(!(init[i] < init[i-1]));
+  }
+  
+  // now initialise the vector; link neighbours in the sequence
+  for(unsigned int i = 0; i < n; i++) {
+    _nodes[i].value = init[i];
+    _nodes[i].predecessor = (& (_nodes[i])) - 1;
+    _nodes[i].successor   = (& (_nodes[i])) + 1;
+    _nodes[i].nullify_treelinks();
+  }
+  // make a loop structure so that we can circulate...
+  _nodes[0].predecessor = (& (_nodes[n-1]));
+  _nodes[n-1].successor = (& (_nodes[0]));
+
+  // now label the rest of the nodes
+  unsigned int scale = (n+1)/2;
+  unsigned int top   = std::min(n-1,scale);
+  _nodes[top].parent = NULL;
+  _top_node = &(_nodes[top]);
+  _do_initial_connections(top, scale, 0, n, 0);
+
+  // make sure things are sensible...
+  //verify_structure();
+}
+
+
+
+//----------------------------------------------------------------------
+template<class T> inline  int SearchTree<T>::loc(const Node * node) const {return node == NULL? 
+      -999 : node - &(_nodes[0]);}
+
+
+//----------------------------------------------------------------------
+/// Recursive creation of connections, assuming the _nodes vector is
+/// completely filled and ordered
+template<class T> void SearchTree<T>::_do_initial_connections(
+                                         unsigned int this_one, 
+					 unsigned int scale,
+					 unsigned int left_edge,
+					 unsigned int right_edge,
+					 unsigned int depth
+					 ) {
+
+#ifdef TRACK_DEPTH
+  // keep track of tree depth for checking things stay reasonable...
+  _max_depth = max(depth, _max_depth);
+#endif
+
+  //std::cout << this_one << " "<< scale<< std::endl;
+  unsigned int ref_new_scale = (scale+1)/2;
+
+  // work through children to our left
+  unsigned new_scale = ref_new_scale;
+  bool     did_child  = false;
+  while(true) {
+    int left = this_one - new_scale; // be careful here to use signed int...
+    // if there is something unitialised to our left, link to it
+    if (left >= static_cast<int>(left_edge) 
+	                && _nodes[left].treelinks_null() ) {
+      _nodes[left].parent = &(_nodes[this_one]);
+      _nodes[this_one].left = &(_nodes[left]);
+      // create connections between left_edge and this_one
+      _do_initial_connections(left, new_scale, left_edge, this_one, depth+1);
+      did_child = true;
+      break;
+    }
+    // reduce the scale so as to try again
+    unsigned int old_new_scale = new_scale;
+    new_scale = (old_new_scale + 1)/2;
+    // unless we've reached end of tree
+    if (new_scale == old_new_scale) break;
+  }
+  if (!did_child) {_nodes[this_one].left = NULL;}
+
+
+  // work through children to our right
+  new_scale = ref_new_scale;
+  did_child  = false;
+  while(true) {
+    unsigned int right = this_one + new_scale;
+    if (right < right_edge  && _nodes[right].treelinks_null()) {
+      _nodes[right].parent = &(_nodes[this_one]);
+      _nodes[this_one].right = &(_nodes[right]);
+      // create connections between this_one+1 and right_edge
+      _do_initial_connections(right, new_scale, this_one+1,right_edge,depth+1);
+      did_child = true;
+      break;
+    }
+    // reduce the scale so as to try again
+    unsigned int old_new_scale = new_scale;
+    new_scale = (old_new_scale + 1)/2;
+    // unless we've reached end of tree
+    if (new_scale == old_new_scale) break;
+  }
+  if (!did_child) {_nodes[this_one].right = NULL;}
+
+}
+
+
+
+//----------------------------------------------------------------------
+template<class T> void SearchTree<T>::remove(unsigned int node_index) {
+  remove(&(_nodes[node_index]));
+}
+
+//----------------------------------------------------------------------
+template<class T> void SearchTree<T>::remove(circulator & circ) {
+  remove(circ._node);
+}
+
+//----------------------------------------------------------------------
+// Useful reference for this:
+//   http://en.wikipedia.org/wiki/Binary_search_tree#Deletion
+template<class T> void SearchTree<T>::remove(typename SearchTree<T>::Node * node) {
+
+  // we don't remove things from the tree if we've reached the last
+  // elements... (is this wise?)
+  assert(size() > 1); // switch this to throw...?
+  assert(!node->treelinks_null());
+
+  // deal with relinking predecessor and successor
+  node->predecessor->successor = node->successor;
+  node->successor->predecessor = node->predecessor;
+
+  if (node->left == NULL && node->right == NULL) {
+    // node has no children, so remove it by nullifying the pointer 
+    // from the parent
+    node->reset_parents_link_to_me(NULL); 
+
+  } else if (node->left != NULL && node->right == NULL){
+    // make parent point to my child
+    node->reset_parents_link_to_me(node->left);
+    // and child to parent
+    node->left->parent = node->parent;         
+    // sort out the top node...
+    if (_top_node == node) {_top_node = node->left;}
+
+  } else if (node->left == NULL && node->right != NULL){
+    // make parent point to my child
+    node->reset_parents_link_to_me(node->right);
+    // and child to parent
+    node->right->parent = node->parent;   
+    // sort out the top node...
+    if (_top_node == node) {_top_node = node->right;}
+
+  } else {
+    // we have two children; we will put a replacement in our place
+    Node * replacement;
+    //SearchTree<T>::Node * replacements_child;
+    // chose predecessor or successor (one, then other, then first, etc...)
+    bool use_predecessor = (_n_removes % 2 == 1);
+    if (use_predecessor) {
+      // Option 1: put predecessor in our place, and have its parent
+      // point to its left child (as a predecessor it has no right child)
+      replacement = node->predecessor;
+      assert(replacement->right == NULL); // guaranteed if it's our predecessor
+      // we have to be careful of replacing certain links when the 
+      // replacement is this node's child
+      if (replacement != node->left) {
+	if (replacement->left != NULL) {
+	  replacement->left->parent = replacement->parent;}
+	replacement->reset_parents_link_to_me(replacement->left);
+	replacement->left   = node->left;
+      }
+      replacement->parent = node->parent;
+      replacement->right  = node->right;
+    } else {
+      // Option 2: put successor in our place, and have its parent
+      // point to its right child (as a successor it has no left child)
+      replacement = node->successor;
+      assert(replacement->left == NULL); // guaranteed if it's our successor
+      if (replacement != node->right) {
+	if (replacement->right != NULL) {
+	  replacement->right->parent = replacement->parent;}
+	replacement->reset_parents_link_to_me(replacement->right);
+	replacement->right  = node->right;
+      }
+      replacement->parent = node->parent;
+      replacement->left   = node->left;
+    }
+    node->reset_parents_link_to_me(replacement);
+
+    // make sure node's original children now point to the replacement
+    if (node->left  != replacement) {node->left->parent  = replacement;}
+    if (node->right != replacement) {node->right->parent = replacement;}
+
+    // sort out the top node...
+    if (_top_node == node) {_top_node = replacement;}
+  }
+
+  // make sure we leave something nice and clean...
+  node->nullify_treelinks();
+  node->predecessor = NULL;
+  node->successor   = NULL;
+
+  // for bookkeeping (and choosing whether to use pred. or succ.)
+  _n_removes++;
+  // for when we next need access to a free node...
+  _available_nodes.push_back(node);
+}
+
+
+//----------------------------------------------------------------------
+//template<class T> typename SearchTree<T>::Node * SearchTree<T>::insert(const T & value) {
+
+//----------------------------------------------------------------------
+template<class T> typename SearchTree<T>::circulator SearchTree<T>::insert(const T & value) {
+  // make sure we don't exceed allowed number of nodes...
+  assert(_available_nodes.size() > 0);
+
+  Node * node = _available_nodes.back();
+  _available_nodes.pop_back();
+  node->value = value;
+
+  Node * location = _top_node;
+  Node * old_location = NULL;
+  bool             on_left = true; // (init not needed -- but soothes g++4)
+  // work through tree until we reach its end
+#ifdef TRACK_DEPTH
+  unsigned int depth = 0;
+#endif
+  while(location != NULL) {
+#ifdef TRACK_DEPTH
+    depth++;
+#endif
+    old_location = location;
+    on_left = value < location->value;
+    if (on_left) {location = location->left;}
+    else {location = location->right;}
+  }
+#ifdef TRACK_DEPTH
+  _max_depth = max(depth, _max_depth);
+#endif
+  // now create tree links
+  node->parent = old_location;
+  if (on_left) {node->parent->left = node;} 
+  else {node->parent->right = node;}
+  node->left = NULL;
+  node->right = NULL;
+  // and create predecessor / successor links
+  node->predecessor = _find_predecessor(node);
+  if (node->predecessor != NULL) {
+    // it exists, so make use of its info (will include a cyclic case,
+    // when successor is round the bend)
+    node->successor = node->predecessor->successor;
+    node->predecessor->successor = node;
+    node->successor->predecessor = node;
+  } else {
+    // deal with case when we are left-most edge of tree (then successor
+    // will exist...)
+    node->successor = _find_successor(node);
+    assert(node->successor != NULL); // can only happen if we're sole element 
+                                     // (but not allowed, since tree size>=1)
+    node->predecessor = node->successor->predecessor;
+    node->successor->predecessor = node;
+    node->predecessor->successor = node;
+  }
+
+  return circulator(node);
+}
+
+
+//----------------------------------------------------------------------
+template<class T> void SearchTree<T>::verify_structure() {
+  
+  // do a check running through all elements
+  verify_structure_linear();
+
+  // do a recursive check down tree from top
+
+  // first establish the extremities
+  const Node * left_limit = _top_node;
+  while (left_limit->left != NULL) {left_limit = left_limit->left;}
+  const Node * right_limit = _top_node;
+  while (right_limit->right != NULL) {right_limit = right_limit->right;}
+
+  // then actually do recursion
+  verify_structure_recursive(_top_node, left_limit, right_limit);
+}
+
+
+//----------------------------------------------------------------------
+template<class T> void SearchTree<T>::verify_structure_recursive(
+		      const typename SearchTree<T>::Node * element, 
+		      const typename SearchTree<T>::Node * left_limit,
+		      const typename SearchTree<T>::Node * right_limit)  const {
+
+  assert(!(element->value < left_limit->value));
+  assert(!(right_limit->value < element->value));
+
+  const Node * left = element->left;
+  if (left != NULL) {
+    assert(!(element->value < left->value));
+    if (left != left_limit) {
+      // recurse down the tree with this element as the right-hand limit
+      verify_structure_recursive(left, left_limit, element);}
+  }
+  
+  const Node * right = element->right;
+  if (right != NULL) {
+    assert(!(right->value < element->value));
+    if (right != right_limit) {
+      // recurse down the tree with this element as the left-hand limit
+      verify_structure_recursive(right, element, right_limit);}
+  }
+}
+
+//----------------------------------------------------------------------
+template<class T> void SearchTree<T>::verify_structure_linear() const {
+
+  //print_elements();
+
+  unsigned n_top = 0;
+  unsigned n_null = 0;
+  for(unsigned i = 0; i < _nodes.size(); i++) {
+    const typename SearchTree<T>::Node * node = &(_nodes[i]);
+    // make sure node is defined
+    if (node->treelinks_null()) {n_null++; continue;}
+
+    // make sure of the number of "top" nodes 
+    if (node->parent == NULL) {
+      n_top++;
+      //assert(node->left != NULL);
+      //assert(node->right != NULL);
+    } else {
+      // make sure that I am a child of my parent...
+      //assert((node->parent->left == node) || (node->parent->right == node));
+      assert((node->parent->left == node) ^ (node->parent->right == node));
+    }
+
+    // when there is a left child make sure it's value is ordered
+    // (note use of !(b<a), to allow for a<=b while using just the <
+    // operator)
+    if (node->left != NULL) {
+      assert(!(node->value < node->left->value ));}
+
+    // when there is a right child make sure it's value is ordered
+    if (node->right != NULL) {
+      assert(!(node->right->value < node->value ));}
+
+  }
+  assert(n_top == 1 || (n_top == 0 && size() <= 1) );
+  assert(n_null == _available_nodes.size() ||
+	 (n_null == _available_nodes.size() + 1 && size() == 1));
+}
+
+
+//----------------------------------------------------------------------
+template<class T> typename SearchTree<T>::Node * SearchTree<T>::_find_predecessor(const typename SearchTree<T>::Node * node) {
+
+  typename SearchTree<T>::Node * newnode;
+  if (node->left != NULL) {
+    // go down left, and then down right as far as possible.
+    newnode = node->left;
+    while(newnode->right != NULL) {newnode = newnode->right;}
+    return newnode;
+  } else {
+    const typename SearchTree<T>::Node * lastnode = node;
+    newnode = node->parent;
+    // go up the tree as long as we're going right (when we go left then
+    // we've found something smaller, so stop)
+    while(newnode != NULL) {
+      if (newnode->right == lastnode) {return newnode;}
+      lastnode = newnode;
+      newnode = newnode->parent;
+    }
+    return newnode;
+  }
+}
+
+
+//----------------------------------------------------------------------
+template<class T> typename SearchTree<T>::Node * SearchTree<T>::_find_successor(const typename SearchTree<T>::Node * node) {
+
+  typename SearchTree<T>::Node * newnode;
+  if (node->right != NULL) {
+    // go down right, and then down left as far as possible.
+    newnode = node->right;
+    while(newnode->left != NULL) {newnode = newnode->left;}
+    return newnode;
+  } else {
+    const typename SearchTree<T>::Node * lastnode = node;
+    newnode = node->parent;
+    // go up the tree as long as we're going left (when we go right then
+    // we've found something larger, so stop)
+    while(newnode != NULL) {
+      if (newnode->left == lastnode) {return newnode;}
+      lastnode = newnode;
+      newnode = newnode->parent;
+    }
+    return newnode;
+  }
+}
+
+
+//----------------------------------------------------------------------
+// print out all the elements for visual checking...
+template<class T> void SearchTree<T>::print_elements() {
+  typename SearchTree<T>::Node * base_node = &(_nodes[0]);
+  typename SearchTree<T>::Node * node = base_node;
+  
+  int n = _nodes.size();
+  for(; node - base_node < n ; node++) {
+    printf("%4d parent:%4d left:%4d right:%4d pred:%4d succ:%4d value:%10.6f\n",loc(node), loc(node->parent), loc(node->left), loc(node->right), loc(node->predecessor),loc(node->successor),node->value);
+  }
+}
+
+//----------------------------------------------------------------------
+template<class T> typename SearchTree<T>::circulator SearchTree<T>::somewhere() {
+  return circulator(_top_node);
+}
+
+
+//----------------------------------------------------------------------
+template<class T> typename SearchTree<T>::const_circulator SearchTree<T>::somewhere() const {
+  return const_circulator(_top_node);
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_SEARCHTREE_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/Triangulation.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/Triangulation.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/Triangulation.hh	(revision 11)
@@ -0,0 +1,100 @@
+//STARTHEADER
+// $Id: Triangulation.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#ifndef __FASTJET_TRIANGULATION__
+#define __FASTJET_TRIANGULATION__
+
+// file: examples/Triangulation_2/Voronoi.C
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Delaunay_triangulation_2.h>
+#include <CGAL/Triangulation_hierarchy_2.h>
+#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+#include "fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// the basic geometrical kernel that lies at the base of all CGAL
+/// operations
+#ifdef CGAL_SIMPLE_KERNEL
+struct K : CGAL::Simple_cartesian<double> {};
+#else
+struct K : CGAL::Exact_predicates_inexact_constructions_kernel {};
+#endif // CGAL_SIMPLE_KERNEL
+
+// our extras to help us navigate, find distance, etc.
+const int INFINITE_VERTEX=-1;
+const int NEW_VERTEX=-2;
+const double HUGE_DOUBLE=1e300;
+
+/// A class to provide an "int" with an initial value.
+class InitialisedInt {
+ private:
+  int _val;
+ public:
+  inline InitialisedInt () {_val=NEW_VERTEX;};
+  inline InitialisedInt& operator= (int value) {_val = value; return *this;};
+  inline int val() const {return _val;};
+};
+
+
+// We can have triangulations with and without hierarchies -- those with 
+// are able to guarantee N ln N time for the construction of a large
+// triangulation, whereas those without go as N^{3/2} for points
+// sufficiently uniformly distributed in a plane.
+//
+//#define NOHIERARCHY
+#ifdef NOHIERARCHY
+typedef CGAL::Triangulation_vertex_base_with_info_2<InitialisedInt,K> Vb;
+typedef CGAL::Triangulation_face_base_2<K> Fb;
+typedef CGAL::Triangulation_data_structure_2<Vb,Fb> Tds;
+typedef CGAL::Delaunay_triangulation_2<K,Tds>  Triangulation;
+#else
+typedef CGAL::Triangulation_vertex_base_with_info_2<InitialisedInt,K> Vbb;
+typedef CGAL::Triangulation_hierarchy_vertex_base_2<Vbb> Vb;
+typedef CGAL::Triangulation_face_base_2<K> Fb;
+typedef CGAL::Triangulation_data_structure_2<Vb,Fb> Tds;
+typedef CGAL::Delaunay_triangulation_2<K,Tds>  Dt;
+typedef CGAL::Triangulation_hierarchy_2<Dt> Triangulation;
+#endif
+
+typedef Triangulation::Vertex_handle  Vertex_handle;
+typedef Triangulation::Point          Point; /// CGAL Point structure
+typedef Triangulation::Vertex_circulator Vertex_circulator;
+typedef Triangulation::Face_circulator Face_circulator;
+typedef Triangulation::Face_handle Face_handle;
+
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_TRIANGULATION__
+#endif //  DROP_CGAL 
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/Voronoi.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/Voronoi.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/Voronoi.hh	(revision 11)
@@ -0,0 +1,320 @@
+#ifndef __FASTJET__VORONOI_H__
+#define __FASTJET__VORONOI_H__
+
+//STARTHEADER
+// $Id: Voronoi.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 1994 by AT&T Bell Laboratories (see below)
+//
+//
+//----------------------------------------------------------------------
+// This file is included as part of FastJet but was mostly written by
+// S. Fortune in C, put into C++ with memory management by S
+// O'Sullivan, and with further interface and memeory management
+// modifications by Gregory Soyez.
+//
+// Permission to use, copy, modify, and distribute this software for
+// any purpose without fee is hereby granted, provided that this
+// entire notice is included in all copies of any software which is or
+// includes a copy or modification of this software and in all copies
+// of the supporting documentation for such software. THIS SOFTWARE IS
+// BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY.
+// IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY REPRESENTATION
+// OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
+// SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+//
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+/*
+* The author of this software is Steven Fortune.  
+* Copyright (c) 1994 by AT&T Bell Laboratories.
+* Permission to use, copy, modify, and distribute this software for any
+* purpose without fee is hereby granted, provided that this entire notice
+* is included in all copies of any software which is or includes a copy
+* or modification of this software and in all copies of the supporting
+* documentation for such software.
+* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+* WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+*/
+
+/* 
+* This code was originally written by Stephan Fortune in C code.  I,
+* Shane O'Sullivan, have since modified it, encapsulating it in a C++
+* class and, fixing memory leaks and adding accessors to the Voronoi
+* Edges.  Permission to use, copy, modify, and distribute this
+* software for any purpose without fee is hereby granted, provided
+* that this entire notice is included in all copies of any software
+* which is or includes a copy or modification of this software and in
+* all copies of the supporting documentation for such software.  THIS
+* SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+* WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+* PURPOSE.
+*/
+
+#include "Utilities/Fastjet/include/fastjet/ClusterSequenceWithArea.hh"
+#include <vector>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DELETED -2
+#define le 0
+#define re 1
+
+//using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/**
+ * \class Point
+ * class to handle a 2d point
+ */
+class Point{
+public:
+  /// defailt ctor
+  Point() : x(0.0), y(0.0) {}
+
+  /// ctor with initialisation
+  Point(double _x, double _y) : x(_x), y(_y) {}
+
+  /// addition
+  inline Point operator + (const Point &p) const{
+    return Point(x+p.x, y+p.y);
+  }
+
+  /// subtraction
+  inline Point operator - (const Point &p) const{
+    return Point(x-p.x, y-p.y);
+  }
+
+  /// scalar multiplication
+  inline Point operator * (const double t) const{
+    return Point(x*t, y*t);
+  }
+
+  /// vector coordinates
+  double x,y;
+};
+
+
+/// norm of a vector
+inline double norm(const Point p){
+  return p.x*p.x+p.y*p.y;
+}
+
+
+/// 2D vector product
+inline double vector_product(const Point &p1, const Point &p2){
+  return p1.x*p2.y-p1.y*p2.x;
+}
+
+
+/// scalar product
+inline double scalar_product(const Point &p1, const Point &p2){
+  return p1.x*p2.x+p1.y*p2.y;
+}
+
+
+/**
+ * \class GraphEdge
+ * handle an edge of the Voronoi Diagram.
+ */
+class GraphEdge{
+public:
+  /// coordinates of the extreme points
+  double x1,y1,x2,y2;
+
+  /// indices of the parent sites that define the edge
+  int point1, point2;
+
+  /// pointer to the next edge
+  GraphEdge* next;
+};
+
+
+/**
+ * \class Site
+ * structure used both for particle sites and for vertices.
+ */
+class Site{
+ public:
+  Point	coord;
+  int sitenbr;
+  int refcnt;
+};
+
+
+
+class Freenode{
+public:
+  Freenode *nextfree;
+};
+
+
+class FreeNodeArrayList{
+public:
+  Freenode* memory;
+  FreeNodeArrayList* next;
+};
+
+
+class Freelist{
+public:
+  Freenode *head;
+  int nodesize;
+};
+
+class Edge{
+public:
+  double a,b,c;
+  Site *ep[2];
+  Site *reg[2];
+  int edgenbr;
+};
+
+
+class Halfedge{
+public:
+  Halfedge *ELleft, *ELright;
+  Edge *ELedge;
+  int ELrefcnt;
+  char ELpm;
+  Site *vertex;
+  volatile double ystar;
+  Halfedge *PQnext;
+};
+
+
+class VoronoiDiagramGenerator{
+public:
+  VoronoiDiagramGenerator();
+  ~VoronoiDiagramGenerator();
+
+  bool generateVoronoi(std::vector<Point> *_parent_sites,
+		       double minX, double maxX, double minY, double maxY, 
+		       double minDist=0);
+
+  inline void resetIterator(){
+    iteratorEdges = allEdges;
+  }
+
+  bool getNext(GraphEdge **e){
+    if(iteratorEdges == 0)
+      return false;
+    
+    *e = iteratorEdges;
+    iteratorEdges = iteratorEdges->next;
+    return true;
+  }
+  
+  std::vector<Point> *parent_sites;
+  int n_parent_sites;
+
+private:
+  void cleanup();
+  void cleanupEdges();
+  char *getfree(Freelist *fl);	
+  Halfedge *PQfind();
+  int PQempty();
+	
+  Halfedge **ELhash;
+  Halfedge *HEcreate(), *ELleft(), *ELright(), *ELleftbnd();
+  Halfedge *HEcreate(Edge *e,int pm);
+  
+  Point PQ_min();
+  Halfedge *PQextractmin();	
+  void freeinit(Freelist *fl,int size);
+  void makefree(Freenode *curr,Freelist *fl);
+  void geominit();
+  void plotinit();
+  bool voronoi(int triangulate);
+  void ref(Site *v);
+  void deref(Site *v);
+  void endpoint(Edge *e,int lr,Site * s);
+
+  void ELdelete(Halfedge *he);
+  Halfedge *ELleftbnd(Point *p);
+  Halfedge *ELright(Halfedge *he);
+  void makevertex(Site *v);
+  void out_triple(Site *s1, Site *s2,Site * s3);
+  
+  void PQinsert(Halfedge *he,Site * v, double offset);
+  void PQdelete(Halfedge *he);
+  bool ELinitialize();
+  void ELinsert(Halfedge *lb, Halfedge *newHe);
+  Halfedge * ELgethash(int b);
+  Halfedge *ELleft(Halfedge *he);
+  Site *leftreg(Halfedge *he);
+  void out_site(Site *s);
+  bool PQinitialize();
+  int PQbucket(Halfedge *he);
+  void clip_line(Edge *e);
+  char *myalloc(unsigned n);
+  int right_of(Halfedge *el,Point *p);
+
+  Site *rightreg(Halfedge *he);
+  Edge *bisect(Site *s1, Site *s2);
+  double dist(Site *s,Site *t);
+  Site *intersect(Halfedge *el1, Halfedge *el2, Point *p=0);
+
+  void out_bisector(Edge *e);
+  void out_ep(Edge *e);
+  void out_vertex(Site *v);
+  Site *nextone();
+
+  void pushGraphEdge(double x1, double y1, double x2, double y2, 
+		     Site *s1, Site *s2);
+
+  void openpl();
+  void circle(double x, double y, double radius);
+  void range(double minX, double minY, double maxX, double maxY);
+
+  Freelist hfl;
+  Halfedge *ELleftend, *ELrightend;
+  int ELhashsize;
+  
+  int triangulate, sorted, plot, debug;
+  double xmin, xmax, ymin, ymax, deltax, deltay;
+  
+  Site *sites;
+  int nsites;
+  int siteidx;
+  int sqrt_nsites;
+  int nvertices;
+  Freelist sfl;
+  Site *bottomsite;
+  
+  int nedges;
+  Freelist efl;
+  int PQhashsize;
+  Halfedge *PQhash;
+  int PQcount;
+  int PQmin;
+  
+  int ntry, totalsearch;
+  double pxmin, pxmax, pymin, pymax, cradius;
+  int total_alloc;
+  
+  double borderMinX, borderMaxX, borderMinY, borderMaxY;
+  
+  FreeNodeArrayList* allMemoryList;
+  FreeNodeArrayList* currentMemoryBlock;
+  
+  GraphEdge* allEdges;
+  GraphEdge* iteratorEdges;
+  
+  double minDistanceBetweenSites;
+};
+
+int scomp(const void *p1,const void *p2);
+
+
+FASTJET_END_NAMESPACE
+
+#endif
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/base.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/base.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/base.hh	(revision 11)
@@ -0,0 +1,40 @@
+
+//STARTHEADER
+// $Id: base.hh,v 1.1 2008-11-06 14:32:10 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_FASTJET_BASE_HH__
+#define __FASTJET_FASTJET_BASE_HH__
+
+// define this for easier readability (and obfuscation?) in
+// a range of places
+#define FASTJET_BEGIN_NAMESPACE namespace fastjet {
+#define FASTJET_END_NAMESPACE   }
+
+#endif // __FASTJET_FASTJET_BASE_HH__
Index: /trunk/Utilities/Fastjet/include/fastjet/internal/numconsts.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/internal/numconsts.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/internal/numconsts.hh	(revision 11)
@@ -0,0 +1,53 @@
+//STARTHEADER
+// $Id: numconsts.hh,v 1.1 2008-11-06 14:32:10 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+
+#ifndef __FASTJET_NUMCONSTS__
+#define __FASTJET_NUMCONSTS__
+
+#include "Utilities/Fastjet/include/fastjet/internal/base.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+// some common useful constants!
+
+const double pi = 3.141592653589793238462643383279502884197;
+const double twopi = 6.283185307179586476925286766559005768394;
+const double pisq  = 9.869604401089358618834490999876151135314;
+const double zeta2 = 1.644934066848226436472415166646025189219;
+const double zeta3 = 1.202056903159594285399738161511449990765;
+const double eulergamma = 0.577215664901532860606512090082402431042;
+const double ln2   = 0.693147180559945309417232121458176568076;
+
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_NUMCONSTS__
Index: /trunk/Utilities/Fastjet/include/fastjet/version.hh
===================================================================
--- /trunk/Utilities/Fastjet/include/fastjet/version.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/include/fastjet/version.hh	(revision 11)
@@ -0,0 +1,43 @@
+//STARTHEADER
+// $Id: version.hh,v 1.1 2008-11-06 14:32:09 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __FASTJET_VERSION_HH__
+#define __FASTJET_VERSION_HH__
+
+#include<string>
+#include "config.h"
+
+FASTJET_BEGIN_NAMESPACE
+
+const char* fastjet_version = PACKAGE_VERSION;
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_VERSION_HH__
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.cc	(revision 11)
@@ -0,0 +1,172 @@
+//STARTHEADER
+// $Id: CDFJetCluPlugin.cc,v 1.1 2008-11-06 14:32:10 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "CDFJetCluPlugin.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence.hh"
+#include <sstream>
+#include <cassert>
+
+// CDF stuff
+#include "interface/JetCluAlgorithm.hh"
+#include "interface/PhysicsTower.hh"
+#include "interface/Cluster.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+string CDFJetCluPlugin::description () const {
+  ostringstream desc;
+  
+  desc << "CDF JetClu jet algorithm with " 
+       << "seed_threshold = "     << seed_threshold    () << ", "
+       << "cone_radius = "        << cone_radius       () << ", "
+       << "adjacency_cut = "      << adjacency_cut     () << ", " 
+       << "max_iterations = "     << max_iterations    () << ", "
+       << "iratch = "             << iratch            () << ", "
+       << "overlap_threshold = "  << overlap_threshold () ;
+
+  return desc.str();
+}
+
+
+void CDFJetCluPlugin::run_clustering(ClusterSequence & clust_seq) const {
+ 
+  // create the physics towers needed by the CDF code
+  vector<PhysicsTower> towers;
+  towers.reserve(clust_seq.jets().size());
+
+  // create a map to identify jets (actually just the input particles)...
+  //map<double,int> jetmap;
+
+  for (unsigned i = 0; i < clust_seq.jets().size(); i++) {
+    PseudoJet particle(clust_seq.jets()[i]);
+    //_insert_unique(particle, jetmap);
+    LorentzVector fourvect(particle.px(), particle.py(),
+			   particle.pz(), particle.E());
+    PhysicsTower tower(fourvect);
+    // add tracking information for later
+    tower.fjindex = i;
+    towers.push_back(tower);
+  }
+
+  // prepare the CDF algorithm
+  JetCluAlgorithm j(seed_threshold(), cone_radius(), adjacency_cut(),
+                    max_iterations(), iratch(), overlap_threshold());
+    
+  // run the CDF algorithm
+  std::vector<Cluster> jets;
+  j.run(towers,jets);
+
+
+  // now transfer the jets back into our own structure -- we will
+  // mimic the cone code with a sequential recombination sequence in
+  // which the jets are built up by adding one particle at a time
+
+  // NB: with g++-4.0, the reverse iterator code gave problems, so switch
+  //     to indices instead
+  //for(vector<Cluster>::const_reverse_iterator jetIter = jets.rbegin(); 
+  //                                    jetIter != jets.rend(); jetIter++) {
+  //  const vector<PhysicsTower> & tower_list = jetIter->towerList;
+  //  int jet_k = jetmap[tower_list[0].fourVector.E];
+  //
+  //  int ntow = int(jetIter->towerList.size());
+
+  for(int iCDFjets = jets.size()-1; iCDFjets >= 0; iCDFjets--) {
+    const vector<PhysicsTower> & tower_list = jets[iCDFjets].towerList;
+    //int jet_k = jetmap[tower_list[0].fourVector.E];
+    int jet_k = tower_list[0].fjindex;
+  
+    int ntow = int(tower_list.size());
+    for (int itow = 1; itow < ntow; itow++) {
+      int jet_i = jet_k;
+      // retrieve our misappropriated index for the jet
+      int jet_j;
+      jet_j = tower_list[itow].fjindex;
+      //int alt_jet_j = jetmap[tower_list[itow].fourVector.E];
+      //assert(jet_j == alt_jet_j);
+      //cout << jet_j << endl;
+      // safety check
+      assert (jet_j >= 0 && jet_j < int(towers.size()));
+      // do a fake recombination step with dij=0
+      double dij = 0.0;
+      // JetClu does E-scheme recombination so we can stick with the
+      // simple option
+      clust_seq.plugin_record_ij_recombination(jet_i, jet_j, dij, jet_k);
+      //if (itow != ntow) {
+      //  clust_seq.plugin_record_ij_recombination(jet_i, jet_j, dij, jet_k);
+      //} else {
+      //  clust_seq.plugin_record_ij_recombination(jet_i, jet_j, dij, 
+      //       PseudoJet(jetIter->fourVector.px,jetIter->fourVector.py,
+      //                 jetIter->fourVector.pz,jetIter->fourVector.E),
+      //                                           jet_k);
+      //}
+    }
+  
+    // NB: put a sensible looking d_iB just to be nice...
+    double d_iB = clust_seq.jets()[jet_k].perp2();
+    clust_seq.plugin_record_iB_recombination(jet_k, d_iB);
+  }
+
+
+  // following code is for testing only
+  //cout << endl;
+  //for(vector<Cluster>::const_iterator jetIter = jets.begin(); 
+  //                                    jetIter != jets.end(); jetIter++) {
+  //  cout << jetIter->fourVector.pt() << " " << jetIter->fourVector.y() << endl;
+  //}
+  //cout << "-----------------------------------------------------\n";
+  //vector<PseudoJet> ourjets(clust_seq.inclusive_jets());
+  //for (vector<PseudoJet>::const_iterator ourjet = ourjets.begin();
+  //     ourjet != ourjets.end(); ourjet++) {
+  //  cout << ourjet->perp() << " " << ourjet->rap() << endl;
+  //}
+  //cout << endl;
+}
+
+
+//// following code should now be obsolete since addition of 
+//// index to the physics tower in the CDF code
+// void CDFJetCluPlugin::_insert_unique(PseudoJet & jet, 
+//                                      map<double,int> & jetmap) const {
+//   while (jetmap.find(jet.E()) != jetmap.end()) {
+//     // deal with cases where something else has the same energy, and
+//     // also with situation where that energy is zero.
+//     if (jet.E() != 0.0) {
+//       jet *= 1.0+1e-12;
+//     } else {
+//       jet += PseudoJet(0.0,0.0,0.0,1e-300);
+//     }
+//   }
+//   jetmap[jet.E()] = jet.cluster_hist_index();
+// }
+
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/CDFJetCluPlugin.hh	(revision 11)
@@ -0,0 +1,107 @@
+//STARTHEADER
+// $Id: CDFJetCluPlugin.hh,v 1.1 2008-11-06 14:32:10 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __CDFJETCLUPLUGIN_HH__
+#define __CDFJETCLUPLUGIN_HH__
+
+#include "Utilities/Fastjet/include/fastjet/JetDefinition.hh"
+#include "Utilities/Fastjet/include/fastjet/PseudoJet.hh"
+#include <map>
+
+// questionable whether this should be in fastjet namespace or not...
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+/// a plugin for fastjet-v2.1 that provides an interface to the CDF
+/// jetclu algorithm
+class CDFJetCluPlugin : public JetDefinition::Plugin {
+public:
+  /// a compact constructor
+  CDFJetCluPlugin (double   cone_radius, 
+		   double   overlap_threshold = 0.5, 
+		   double   seed_threshold = 1.0,
+		   int      iratch = 1) : 
+    _seed_threshold    ( seed_threshold    ),    
+    _cone_radius       ( cone_radius       ),
+    _adjacency_cut     (   2               ),
+    _max_iterations    ( 100               ),
+    _iratch            ( iratch            ),
+    _overlap_threshold ( overlap_threshold )  {}
+
+  /// a constructor that looks like the one provided by CDF
+  CDFJetCluPlugin (
+                     double seed_threshold   ,	 
+		     double cone_radius      ,
+		     int    adjacency_cut    ,
+		     int    max_iterations   ,
+		     int    iratch           ,
+		     double overlap_threshold) :
+    _seed_threshold    (seed_threshold    ),    
+    _cone_radius       (cone_radius       ),
+    _adjacency_cut     (adjacency_cut     ),
+    _max_iterations    (max_iterations    ),
+    _iratch            (iratch            ),
+    _overlap_threshold (overlap_threshold )  {}
+
+  // some functions to return info about parameters
+  double seed_threshold    () const {return _seed_threshold    ;}
+  double cone_radius       () const {return _cone_radius       ;}
+  int    adjacency_cut     () const {return _adjacency_cut     ;}
+  int    max_iterations    () const {return _max_iterations    ;}
+  int    iratch            () const {return _iratch            ;}
+  double overlap_threshold () const {return _overlap_threshold ;}
+
+
+  // the things that are required by base class
+  virtual std::string description () const;
+  virtual void run_clustering(ClusterSequence &) const;
+  /// the plugin mechanism's standard way of accessing the jet radius
+  virtual double R() const {return cone_radius();}
+                      
+
+private:
+
+  double _seed_threshold   ;
+  double _cone_radius      ;
+  int    _adjacency_cut    ;
+  int    _max_iterations   ;
+  int    _iratch           ;
+  double _overlap_threshold;
+
+  /// given a jet try inserting its energy into the map -- if that
+  /// energy entry already exists, modify the jet infinitesimally so
+  /// as ensure that the jet energy is unique
+  void _insert_unique (PseudoJet & jet, std::map<double,int> & jetmap) const;
+
+};
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
+
+#endif // __CDFJETCLUPLUGIN_HH__
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.cc	(revision 11)
@@ -0,0 +1,152 @@
+//STARTHEADER
+// $Id: CDFMidPointPlugin.cc,v 1.1 2008-11-06 14:32:10 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "CDFMidPointPlugin.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence.hh"
+#include "Utilities/Fastjet/include/fastjet/Error.hh"
+#include <sstream>
+
+// CDF stuff
+#include "interface/MidPointAlgorithm.hh"
+#include "interface/PhysicsTower.hh"
+#include "interface/Cluster.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+string CDFMidPointPlugin::description () const {
+  ostringstream desc;
+  
+  string sm_scale_string = "split-merge uses ";
+  switch(_sm_scale) {
+  case SM_pt:
+    sm_scale_string += "pt";
+    break;
+  case SM_Et:
+    sm_scale_string += "Et";
+    break;
+  case SM_mt:
+    sm_scale_string += "mt";
+    break;
+  case SM_pttilde:
+    sm_scale_string += "pttilde (scalar sum of pts)";
+    break;
+  default:
+    ostringstream err;
+    err << "Unrecognized split-merge scale choice = " << _sm_scale;
+    throw Error(err.str());
+  }
+
+  
+  if (cone_area_fraction() == 1) {
+    desc << "CDF MidPoint jet algorithm, with " ;
+  } else {
+    desc << "CDF MidPoint+Searchcone jet algorithm, with ";
+  }
+  desc << "seed_threshold = "     << seed_threshold     () << ", "
+       << "cone_radius = "        << cone_radius        () << ", "
+       << "cone_area_fraction = " << cone_area_fraction () << ", " 
+       << "max_pair_size = "      << max_pair_size      () << ", "
+       << "max_iterations = "     << max_iterations     () << ", "
+       << "overlap_threshold  = " << overlap_threshold  () << ", "
+       << sm_scale_string ;
+
+  return desc.str();
+}
+
+
+void CDFMidPointPlugin::run_clustering(ClusterSequence & clust_seq) const {
+ 
+  // create the physics towers needed by the CDF code
+  vector<PhysicsTower> towers;
+  towers.reserve(clust_seq.jets().size());
+  for (unsigned i = 0; i < clust_seq.jets().size(); i++) {
+    LorentzVector fourvect(clust_seq.jets()[i].px(),
+			   clust_seq.jets()[i].py(),
+			   clust_seq.jets()[i].pz(),
+			   clust_seq.jets()[i].E());
+    PhysicsTower tower(fourvect);
+    // misuse one of the indices for tracking, since the MidPoint
+    // implementation doesn't seem to make use of these indices
+    tower.calTower.iEta = i;
+    towers.push_back(tower);
+  }
+
+  // prepare the CDF algorithm
+  MidPointAlgorithm m(_seed_threshold,_cone_radius,_cone_area_fraction,
+		      _max_pair_size,_max_iterations,_overlap_threshold,
+                      MidPointAlgorithm::SplitMergeScale(_sm_scale));
+    
+  // run the CDF algorithm
+  std::vector<Cluster> jets;
+  m.run(towers,jets);
+
+
+  // now transfer the jets back into our own structure -- we will
+  // mimic the cone code with a sequential recombination sequence in
+  // which the jets are built up by adding one particle at a time
+  for(vector<Cluster>::const_iterator jetIter = jets.begin(); 
+                                      jetIter != jets.end(); jetIter++) {
+    const vector<PhysicsTower> & tower_list = jetIter->towerList;
+    int jet_k = tower_list[0].calTower.iEta;
+  
+    int ntow = int(jetIter->towerList.size());
+    for (int itow = 1; itow < ntow; itow++) {
+      int jet_i = jet_k;
+      // retrieve our misappropriated index for the jet
+      int jet_j = tower_list[itow].calTower.iEta;
+      // do a fake recombination step with dij=0
+      double dij = 0.0;
+      clust_seq.plugin_record_ij_recombination(jet_i, jet_j, dij, jet_k);
+    }
+  
+    // NB: put a sensible looking d_iB just to be nice...
+    double d_iB = clust_seq.jets()[jet_k].perp2();
+    clust_seq.plugin_record_iB_recombination(jet_k, d_iB);
+  }
+
+
+  // following code is for testing only
+  //cout << endl;
+  //for(vector<Cluster>::const_iterator jetIter = jets.begin(); 
+  //                                    jetIter != jets.end(); jetIter++) {
+  //  cout << jetIter->fourVector.pt() << " " << jetIter->fourVector.y() << endl;
+  //}
+  //cout << "-----------------------------------------------------\n";
+  //vector<PseudoJet> ourjets(clust_seq.inclusive_jets());
+  //for (vector<PseudoJet>::const_reverse_iterator ourjet = ourjets.rbegin();
+  //     ourjet != ourjets.rend(); ourjet++) {
+  //  cout << ourjet->perp() << " " << ourjet->rap() << endl;
+  //}
+  //cout << endl;
+}
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/CDFMidPointPlugin.hh	(revision 11)
@@ -0,0 +1,163 @@
+//STARTHEADER
+// $Id: CDFMidPointPlugin.hh,v 1.1 2008-11-06 14:32:10 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#ifndef __CDFMIDPOINTPLUGIN_HH__
+#define __CDFMIDPOINTPLUGIN_HH__
+
+#include "Utilities/Fastjet/include/fastjet/JetDefinition.hh"
+
+// questionable whether this should be in fastjet namespace or not...
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+//
+/// CDFMidPointPlugin is a plugin for fastjet (v2.1 upwards) that
+/// provides an interface to the CDF version of Run-II iterative cone
+/// algorithm with midpoint seeds (also known as the Iterative Legacy
+/// Cone Algorithm, ILCA).
+///
+/// The CDF code has been taken from Joey Huston's webpage
+/// http://www.pa.msu.edu/~huston/Les_Houches_2005/Les_Houches_SM.html
+///
+/// Note that the CDF midpoint code contains options that go beyond
+/// those described in the Tevatron run-II document (hep-ex/0005012),
+/// notably search-cones, as described in hep-ph/0111434, and
+/// midpoints bewteen multiplets of stable cones.
+///
+/// Additionally, the version of the CDF midpoint code distributed
+/// here has been modified by the FastJet authors, so as to allow one
+/// to choose the scale used in the split-merge step.
+//
+//----------------------------------------------------------------------
+class CDFMidPointPlugin : public JetDefinition::Plugin {
+public:
+  /// the choice of scale to be used in the split-merge step
+  // NB: just replicates what we've added to the CDF midpoint code
+  enum SplitMergeScale {SM_pt, SM_Et, SM_mt, SM_pttilde};
+
+  ///
+  /// A CDFMidPointPlugin constructor that looks like the one provided
+  /// by CDF. Its arguments should have the following meaning:
+  ///
+  /// - seed_threshold: minimum pt for a particle to be considered 
+  ///   a seed of the iteration.
+  ///
+  /// - cone_radius: standard meaning
+  ///
+  /// - cone_area_fraction: stable-cones are searched for with a
+  ///   radius Rsearch = R * sqrt(cone_area_fraction), and then
+  ///   expanded to size R afterwards; note (hep-ph/0610012) that this
+  ///   introduces IR unsafety at NLO for X+2-jet observables (where X
+  ///   any hard object).
+  ///
+  /// - max_pair_size: "midpoints" can be added between pairs of
+  ///   stable cones, triplets of stable cones, etc.; max_pair_size
+  ///   indicates the maximum number of stable cones that are
+  ///   assembled when adding midpoints.
+  ///
+  /// - max_iterations: the maximum number of iterations to carry out
+  ///   when looking for a stable cone.
+  ///
+  /// - overlap_threshold: if
+  ///     (overlapping_Et)/(Et_of_softer_protojet) < overlap_threshold,
+  ///   overlapping jets are split, otherwise they are merged.
+  ///
+  /// - sm_scale: a choice for the scale to be used in the split-merge
+  ///   step (both for ordering the momenta and quantifying the
+  ///   overlap); the three options are
+  ///
+  ///    . SM_pt: pt (default -- source of small IR safety issue in purely
+  ///      hadronic events)
+  ///
+  ///    . SM_Et: Et (not boost invariant, reduces to mt at zero rapidity and
+  ///      to pt and infinite rapidity)
+  ///
+  ///    . SM_mt: transverse mass = sqrt(m^2+pt^2)
+  ///
+  CDFMidPointPlugin (
+                     double seed_threshold     ,	 
+		     double cone_radius        ,
+		     double cone_area_fraction ,
+		     int    max_pair_size      ,
+		     int    max_iterations     ,
+		     double overlap_threshold  ,
+                     SplitMergeScale sm_scale = SM_pt) :
+    _seed_threshold     (seed_threshold     ),    
+    _cone_radius        (cone_radius        ),
+    _cone_area_fraction (cone_area_fraction ),
+    _max_pair_size      (max_pair_size      ),
+    _max_iterations     (max_iterations     ),
+    _overlap_threshold  (overlap_threshold  ),
+    _sm_scale           (sm_scale)             {}
+
+  /// a compact constructor
+  CDFMidPointPlugin (double   cone_radius, 
+		     double   overlap_threshold = 0.5, 
+		     double   seed_threshold = 1.0,	     
+		     double   cone_area_fraction = 1.0) : 
+    _seed_threshold     (seed_threshold     ),    
+    _cone_radius        (cone_radius        ),
+    _cone_area_fraction (cone_area_fraction ),
+    _max_pair_size      (2                  ),
+    _max_iterations     (100                ),
+    _overlap_threshold  (overlap_threshold  ),
+    _sm_scale           (SM_pt)                {}
+
+
+  // some functions to return info about parameters
+  double seed_threshold     () const {return _seed_threshold     ;}
+  double cone_radius        () const {return _cone_radius        ;}
+  double cone_area_fraction () const {return _cone_area_fraction ;}
+  int    max_pair_size      () const {return _max_pair_size      ;}
+  int    max_iterations     () const {return _max_iterations     ;}
+  double overlap_threshold  () const {return _overlap_threshold  ;}
+
+
+  // the things that are required by base class
+  virtual std::string description () const;
+  virtual void run_clustering(ClusterSequence &) const;
+  /// the plugin mechanism's standard way of accessing the jet radius
+  virtual double R() const {return cone_radius();}
+
+private:
+
+  double _seed_threshold    ;
+  double _cone_radius       ;
+  double _cone_area_fraction;
+  int    _max_pair_size     ;
+  int    _max_iterations    ;
+  double _overlap_threshold ;
+  SplitMergeScale _sm_scale ;
+};
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
+
+#endif // __CDFMIDPOINTPLUGIN_HH__
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/CalTower.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/CalTower.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/CalTower.hh	(revision 11)
@@ -0,0 +1,56 @@
+#ifndef _CAL_TOWER_HH_
+#define _CAL_TOWER_HH_
+
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI  3.141592653589793238462643383279502884197 
+#endif
+
+const double TOWER_THETA[23] = {  3.000,  5.700,  8.400, 11.100, 13.800, 16.500, 19.200, 21.900, 24.600, 27.300, 30.000, 33.524,
+				  36.822, 40.261, 43.614, 47.436, 51.790, 56.735, 62.310, 68.516, 75.297, 82.526, 90.000 };
+
+class CalTower
+{
+ public:
+
+  double Et,eta,phi;
+  int iEta,iPhi;
+
+  CalTower(): Et(0), eta(0), phi(0), iEta(-1), iPhi(-1) {}
+  CalTower(double Et0, double eta0, double phi0): Et(Et0), eta(eta0), phi(phi0)
+  {
+    if(fabs(eta) < -log(tan(TOWER_THETA[0]*M_PI/180/2))){
+      if(eta <= 0){
+	for(int i = 0; i < 22; i++)
+	  if(eta < -log(tan((180 - TOWER_THETA[i + 1])*M_PI/180/2))){
+	    iEta = 4 + i;
+	    break;
+	  }
+      }
+      else{
+	for(int i = 0; i < 22; i++)
+	  if(-eta < -log(tan((180 - TOWER_THETA[i + 1])*M_PI/180/2))){
+	    iEta = 47 - i;
+	    break;
+	  }
+      }
+      if(iEta >= 8 && iEta < 14 || iEta >= 38 && iEta < 44)
+	iPhi = int(phi/2/M_PI*48)%48;
+      else
+	iPhi = int(phi/2/M_PI*24)%24;
+    }
+    else{
+      iEta = -1;
+      iPhi = -1;
+    }
+  }
+  CalTower(double Et0, double eta0, double phi0, int iEta0, int iPhi0): Et(Et0), eta(eta0), phi(phi0), iEta(iEta0), iPhi(iPhi0) {}
+  CalTower(const CalTower& c): Et(c.Et), eta(c.eta), phi(c.phi), iEta(c.iEta), iPhi(c.iPhi) {}
+  bool isEqual(CalTower c)
+  {
+    return Et == c.Et && eta == c.eta && phi == c.phi && iEta == c.iEta && iPhi == c.iPhi;
+  }
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/Centroid.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/Centroid.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/Centroid.hh	(revision 11)
@@ -0,0 +1,57 @@
+#ifndef _CENTROID_HH_
+#define _CENTROID_HH_
+
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI  3.141592653589793238462643383279502884197 
+#endif
+
+class Centroid
+{
+ public:
+
+  double Et,eta,phi;
+
+  Centroid(): Et(0), eta(0), phi(0) {}
+  Centroid(double centroidEt, double centroidEta, double centroidPhi): Et(centroidEt), eta(centroidEta), phi(centroidPhi) {}
+  Centroid(const Centroid& c): Et(c.Et), eta(c.eta), phi(c.phi) {}
+  void add(Centroid c)
+  {
+    double newEt = Et + c.Et;
+    eta = (Et*eta + c.Et*c.eta)/newEt;
+    double dPhi = c.phi - phi;
+    if(dPhi > M_PI)
+      dPhi -= 2*M_PI;
+    else if(dPhi < -M_PI)
+      dPhi += 2*M_PI;
+    phi += dPhi*c.Et/newEt;
+    while(phi < 0)
+      phi += 2*M_PI;
+    while(phi >= 2*M_PI)
+      phi -= 2*M_PI;
+    Et = newEt;
+  }
+  void subtract(Centroid c)
+  {
+    double newEt = Et - c.Et;
+    eta = (Et*eta - c.Et*c.eta)/newEt;
+    double dPhi = c.phi - phi;
+    if(dPhi > M_PI)
+      dPhi -= 2*M_PI;
+    else if(dPhi < -M_PI)
+      dPhi += 2*M_PI;
+    phi -= dPhi*c.Et/newEt;
+    while(phi < 0)
+      phi += 2*M_PI;
+    while(phi >= 2*M_PI)
+      phi -= 2*M_PI;
+    Et = newEt;
+  }
+  bool isEqual(Centroid c)
+  {
+    return Et == c.Et && eta == c.eta && phi == c.phi;
+  }
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/Cluster.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/Cluster.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/Cluster.hh	(revision 11)
@@ -0,0 +1,53 @@
+#ifndef _CLUSTER_HH_
+#define _CLUSTER_HH_
+
+#include "../interface/PhysicsTower.hh"
+#include "../interface/LorentzVector.hh"
+#include "../interface/Centroid.hh"
+#include <vector>
+
+class Cluster
+{
+ public:
+  std::vector<PhysicsTower> towerList;
+  LorentzVector fourVector;
+  Centroid centroid;
+  // addition by G.P.Salam; pt_tilde = sum |p_{ti}|. Maintaining this
+  // seems to add about 1% (3%) to overall timings for midpoint
+  // (jetclu) but it is useful because it makes it easy to look at
+  // other scales in the split-merge procedure
+  double pt_tilde; 
+
+  Cluster()
+  {
+    clear();
+  }
+  void clear()
+  {
+    towerList.clear();
+    fourVector = LorentzVector();
+    centroid = Centroid();
+    pt_tilde = 0.0;
+  }
+  void addTower(PhysicsTower p)
+  {
+    towerList.push_back(p);
+    fourVector.add(p.fourVector);
+    centroid.add(Centroid(p.Et(),p.eta(),p.phi()));
+    pt_tilde += p.fourVector.pt();
+  }
+  void removeTower(PhysicsTower p)
+  {
+    for(std::vector<PhysicsTower>::iterator towerIter = towerList.begin(); towerIter != towerList.end(); towerIter++)
+      if(towerIter->isEqual(p)){
+	fourVector.subtract(towerIter->fourVector);
+	centroid.subtract(Centroid(towerIter->Et(),towerIter->eta(),towerIter->phi()));
+        pt_tilde -= towerIter->fourVector.pt();
+	towerList.erase(towerIter);
+	break;
+      }
+  }
+  int size(){return towerList.size();}
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/ClusterComparisons.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/ClusterComparisons.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/ClusterComparisons.hh	(revision 11)
@@ -0,0 +1,51 @@
+#ifndef _CLUSTER_COMPARISONS_HH_
+#define _CLUSTER_COMPARISONS_HH_
+
+#include "../interface/Cluster.hh"
+
+class ClusterFourVectorEtGreater
+{
+ public:
+  int operator()(const Cluster& c1, const Cluster& c2) const
+  {
+    return c1.fourVector.Et() > c2.fourVector.Et();
+  }
+};
+
+class ClusterCentroidEtGreater
+{
+ public:
+  int operator()(const Cluster& c1, const Cluster& c2) const
+  {
+    return c1.centroid.Et > c2.centroid.Et;
+  }
+};
+
+class ClusterPtGreater
+{
+ public:
+  int operator()(const Cluster& c1, const Cluster& c2) const
+  {
+    return c1.fourVector.pt() > c2.fourVector.pt();
+  }
+};
+
+class ClusterMtGreater
+{
+ public:
+  int operator()(const Cluster& c1, const Cluster& c2) const
+  {
+    return c1.fourVector.mt() > c2.fourVector.mt();
+  }
+};
+
+class ClusterPtTildeGreater
+{
+ public:
+  int operator()(const Cluster& c1, const Cluster& c2) const
+  {
+    return c1.pt_tilde > c2.pt_tilde;
+  }
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/JetCluAlgorithm.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/JetCluAlgorithm.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/JetCluAlgorithm.hh	(revision 11)
@@ -0,0 +1,42 @@
+#ifndef _JETCLU_ALGORITHM_HH_
+#define _JETCLU_ALGORITHM_HH_
+
+#include "../interface/PhysicsTower.hh"
+#include "../interface/Cluster.hh"
+#include <vector>
+
+class JetCluAlgorithm
+{
+ private:
+  double _seedThreshold;
+  double _coneRadius;
+  int    _adjacencyCut;
+  int    _maxIterations;
+  int    _iratch;
+  double _overlapThreshold;
+
+ public:
+  JetCluAlgorithm():
+    _seedThreshold(1),
+    _coneRadius(0.7),
+    _adjacencyCut(2),
+    _maxIterations(100),
+    _iratch(1),
+    _overlapThreshold(0.75)
+  {}
+  JetCluAlgorithm(double st, double cr, int ac, int mi, int ir, double ot):
+    _seedThreshold(st),
+    _coneRadius(cr),
+    _adjacencyCut(ac),
+    _maxIterations(mi),
+    _iratch(ir),
+    _overlapThreshold(ot)
+  {}
+  void makeSeedTowers(std::vector<PhysicsTower>& towers, std::vector<Cluster>& seedTowers);
+  void buildPreClusters(std::vector<Cluster>& seedTowers, std::vector<PhysicsTower>& towers, std::vector<Cluster>& preClusters);
+  void findStableCones(std::vector<Cluster>& preClusters, std::vector<PhysicsTower>& towers, std::vector<Cluster>& stableCones);
+  void splitAndMerge(std::vector<Cluster>& stableCones, std::vector<Cluster>& jets);
+  void run(std::vector<PhysicsTower>& towers, std::vector<Cluster>& jets);
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/LorentzVector.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/LorentzVector.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/LorentzVector.hh	(revision 11)
@@ -0,0 +1,52 @@
+#ifndef _LORENTZ_VECTOR_HH_
+#define _LORENTZ_VECTOR_HH_
+
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI  3.141592653589793238462643383279502884197 
+#endif
+
+class LorentzVector
+{
+ public:
+
+  double px,py,pz,E;
+
+  LorentzVector(): px(0), py(0), pz(0), E(0) {}
+  LorentzVector(double p1, double p2, double p3, double p0): px(p1), py(p2), pz(p3), E(p0) {}
+  LorentzVector(const LorentzVector& p): px(p.px), py(p.py), pz(p.pz), E(p.E) {}
+  double p()   const {return sqrt(px*px + py*py + pz*pz);}
+  double pt()  const {return sqrt(px*px + py*py);}
+  double mt()  const {return sqrt((E-pz)*(E+pz));}
+  double y()   const {return 0.5*log((E + pz)/(E - pz));}
+  double Et()  const {return E/p()*pt();}
+  double eta() const {return 0.5*log((p() + pz)/(p() - pz));}
+  double phi() const
+  {
+    double r = atan2(py,px);
+    if(r < 0)
+      r += 2*M_PI;
+    return r;
+  }
+  void add(LorentzVector v)
+  {
+    px += v.px;
+    py += v.py;
+    pz += v.pz;
+    E  += v.E;
+  }
+  void subtract(LorentzVector v)
+  {
+    px -= v.px;
+    py -= v.py;
+    pz -= v.pz;
+    E  -= v.E;
+  }
+  bool isEqual(LorentzVector v)
+  {
+    return px == v.px && py == v.py && pz == v.pz && E == v.E;
+  }
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/MidPointAlgorithm.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/MidPointAlgorithm.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/MidPointAlgorithm.hh	(revision 11)
@@ -0,0 +1,56 @@
+#ifndef _MIDPOINT_ALGORITHM_HH_
+#define _MIDPOINT_ALGORITHM_HH_
+
+#include "../interface/PhysicsTower.hh"
+#include "../interface/Cluster.hh"
+#include <vector>
+
+class MidPointAlgorithm
+{
+ public:
+  enum SplitMergeScale {SM_pt, SM_Et, SM_mt, SM_pttilde};
+
+ private:
+  double _seedThreshold;
+  double _coneRadius;
+  double _coneAreaFraction;
+  int    _maxPairSize;
+  int    _maxIterations;
+  double _overlapThreshold;
+  SplitMergeScale _smScale;
+
+ public:
+  MidPointAlgorithm():
+    _seedThreshold(1),
+    _coneRadius(0.7),
+    _coneAreaFraction(0.25),
+    _maxPairSize(2),
+    _maxIterations(100),
+    _overlapThreshold(0.75),
+    _smScale(SM_pt)
+  {}
+  MidPointAlgorithm(double st, double cr, double caf, int mps, int mi, double ot, SplitMergeScale sm = SM_pt):
+    _seedThreshold(st),
+    _coneRadius(cr),
+    _coneAreaFraction(caf),
+    _maxPairSize(mps),
+    _maxIterations(mi),
+    _overlapThreshold(ot),
+    _smScale(sm)
+  {}
+  void findStableConesFromSeeds(std::vector<PhysicsTower>& particles, std::vector<Cluster>& stableCones);
+  void findStableConesFromMidPoints(std::vector<PhysicsTower>& particles, std::vector<Cluster>& stableCones);
+  void iterateCone(volatile double startRapidity, volatile double startPhi, volatile double startPt, std::vector<PhysicsTower>& particles,
+		   std::vector<Cluster>& stableCones, bool reduceConeSize);
+  void addClustersToPairs(std::vector<int>& testPair, std::vector< std::vector<int> >& pairs,
+			  std::vector< std::vector<bool> >& distanceOK, int maxClustersInPair);
+  void splitAndMerge(std::vector<Cluster>& stableCones, std::vector<Cluster>& jets);
+  void run(std::vector<PhysicsTower>& particles, std::vector<Cluster>& jets);
+
+  /// sort the clusters into whatever order is 
+  void local_sort(std::vector<Cluster>&);
+
+};
+
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/interface/PhysicsTower.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/interface/PhysicsTower.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/interface/PhysicsTower.hh	(revision 11)
@@ -0,0 +1,33 @@
+#ifndef _PHYSICS_TOWER_HH_
+#define _PHYSICS_TOWER_HH_
+
+#include "../interface/LorentzVector.hh"
+#include "../interface/CalTower.hh"
+
+class PhysicsTower
+{
+ public:
+
+  LorentzVector fourVector;
+  CalTower calTower;
+
+  PhysicsTower(): fourVector(LorentzVector()), calTower(CalTower()), fjindex(-1) {}
+  PhysicsTower(LorentzVector v, CalTower c): fourVector(v), calTower(c), fjindex(-1) {}
+  PhysicsTower(const PhysicsTower& p): fourVector(p.fourVector), calTower(p.calTower), fjindex(p.fjindex) {}
+  PhysicsTower(CalTower c):
+    fourVector(LorentzVector(c.Et*cos(c.phi),c.Et*sin(c.phi),c.Et*sinh(c.eta),c.Et*cosh(c.eta))), calTower(c), fjindex(-1) {}
+  PhysicsTower(LorentzVector v): fourVector(v), calTower(CalTower(v.Et(),v.eta(),v.phi())), fjindex(-1) {}
+  double Et()   const {return calTower.Et;}
+  double eta()  const {return calTower.eta;}
+  double phi()  const {return calTower.phi;}
+  int    iEta() const {return calTower.iEta;}
+  int    iPhi() const {return calTower.iPhi;}
+  bool isEqual(PhysicsTower p)
+  {
+    return fourVector.isEqual(p.fourVector) && calTower.isEqual(p.calTower);
+  }
+  /// addition by GPS (2008-08-15) for tracking within fastjet
+  int fjindex;
+};
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/CalTower.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/CalTower.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/CalTower.cc	(revision 11)
@@ -0,0 +1,1 @@
+#include "../interface/CalTower.hh"
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/Centroid.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/Centroid.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/Centroid.cc	(revision 11)
@@ -0,0 +1,1 @@
+#include "../interface/Centroid.hh"
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/Cluster.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/Cluster.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/Cluster.cc	(revision 11)
@@ -0,0 +1,1 @@
+#include "../interface/Cluster.hh"
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/ClusterComparisons.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/ClusterComparisons.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/ClusterComparisons.cc	(revision 11)
@@ -0,0 +1,1 @@
+#include "../interface/ClusterComparisons.hh"
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/JetCluAlgorithm.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/JetCluAlgorithm.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/JetCluAlgorithm.cc	(revision 11)
@@ -0,0 +1,289 @@
+#include "../interface/JetCluAlgorithm.hh"
+#include "../interface/ClusterComparisons.hh"
+#include "../interface/Centroid.hh"
+#include <algorithm>
+#include <cmath>
+
+void JetCluAlgorithm::makeSeedTowers(std::vector<PhysicsTower>& towers, std::vector<Cluster>& seedTowers)
+{
+  for(int iEta = 4; iEta < 48; iEta++){
+    bool seg24 = true;
+    if(iEta >= 8 && iEta < 14 || iEta >= 38 && iEta < 44)
+      seg24 = false;
+    for(int iPhi = 0; iPhi < 24; iPhi++){
+      Cluster seed;
+      for(std::vector<PhysicsTower>::iterator towerIter = towers.begin(); towerIter != towers.end(); towerIter++)
+	if(towerIter->iEta() == iEta &&
+	   (seg24 && towerIter->iPhi() == iPhi || !seg24 && (towerIter->iPhi() == 2*iPhi || towerIter->iPhi() == 2*iPhi + 1)))
+	  seed.addTower(*towerIter);
+      if(seed.centroid.Et > _seedThreshold)
+	seedTowers.push_back(seed);
+    }
+  }
+  sort(seedTowers.begin(),seedTowers.end(),ClusterCentroidEtGreater());
+}
+
+void JetCluAlgorithm::buildPreClusters(std::vector<Cluster>& seedTowers, std::vector<PhysicsTower>& towers,
+				       std::vector<Cluster>& preClusters)
+{
+  std::vector<Centroid> leadingSeedTowers;
+  for(std::vector<Cluster>::iterator seedTowerIter = seedTowers.begin(); seedTowerIter != seedTowers.end(); seedTowerIter++){
+    bool seedTowerAddedToPreCluster = false;
+    std::vector<Cluster>::iterator preClusterIter = preClusters.begin();
+    std::vector<Centroid>::iterator leadingSeedTowerIter = leadingSeedTowers.begin();
+    while(preClusterIter != preClusters.end() && !seedTowerAddedToPreCluster){
+      double dEta = fabs(seedTowerIter->centroid.eta - leadingSeedTowerIter->eta);
+      double dPhi = fabs(seedTowerIter->centroid.phi - leadingSeedTowerIter->phi);
+      if(dPhi > M_PI)
+	dPhi = 2*M_PI - dPhi;
+      if(dEta <= _coneRadius && dPhi <= _coneRadius){
+	int iEtaSeedTower = seedTowerIter->towerList.begin()->iEta();
+	int iPhiSeedTower = seedTowerIter->towerList.begin()->iPhi();
+	if(iEtaSeedTower >= 8 && iEtaSeedTower < 14 || iEtaSeedTower >= 38 && iEtaSeedTower < 44)
+	  iPhiSeedTower = iPhiSeedTower/2;
+ 	for(std::vector<PhysicsTower>::iterator preClusterTowerIter = preClusterIter->towerList.begin();
+	    preClusterTowerIter != preClusterIter->towerList.end() && !seedTowerAddedToPreCluster;
+	    preClusterTowerIter++){
+	  int iEtaPreClusterTower = preClusterTowerIter->iEta();
+	  int iPhiPreClusterTower = preClusterTowerIter->iPhi();
+	  if(iEtaPreClusterTower >= 8 && iEtaPreClusterTower < 14 || iEtaPreClusterTower >= 38 && iEtaPreClusterTower < 44)
+	    iPhiPreClusterTower = iPhiPreClusterTower/2;
+	  int dIEta = abs(iEtaSeedTower - iEtaPreClusterTower);
+	  int dIPhi = abs(iPhiSeedTower - iPhiPreClusterTower);
+	  if(dIPhi > 12)
+	    dIPhi = 24 - dIPhi;
+	  int adj = dIPhi*dIPhi + dIEta*dIEta;
+	  if(adj <= _adjacencyCut){
+	    for(std::vector<PhysicsTower>::iterator seedTowerTowerIter = seedTowerIter->towerList.begin();
+		seedTowerTowerIter != seedTowerIter->towerList.end();
+		seedTowerTowerIter++)
+	      preClusterIter->addTower(*seedTowerTowerIter);
+	    seedTowerAddedToPreCluster = true;
+	  }
+	}
+      }
+      preClusterIter++;
+      leadingSeedTowerIter++;
+    }
+    if(!seedTowerAddedToPreCluster){
+      Cluster newPreCluster;
+      for(std::vector<PhysicsTower>::iterator seedTowerTowerIter = seedTowerIter->towerList.begin();
+	  seedTowerTowerIter != seedTowerIter->towerList.end();
+	  seedTowerTowerIter++)
+	newPreCluster.addTower(*seedTowerTowerIter);
+      preClusters.push_back(newPreCluster);
+      leadingSeedTowers.push_back(Centroid(newPreCluster.centroid.Et,newPreCluster.centroid.eta,newPreCluster.centroid.phi));
+    }
+  }
+}
+
+void JetCluAlgorithm::findStableCones(std::vector<Cluster>& preClusters, std::vector<PhysicsTower>& towers,
+				      std::vector<Cluster>& stableCones)
+{
+  for(std::vector<Cluster>::iterator preClusterIter = preClusters.begin(); preClusterIter != preClusters.end(); preClusterIter++){
+    double startEt  = preClusterIter->centroid.Et;
+    double startEta = preClusterIter->centroid.eta;
+    double startPhi = preClusterIter->centroid.phi;
+    int nIterations = 0;
+    Cluster trialCone;
+    while(nIterations++ < _maxIterations){
+      trialCone.clear();
+      for(std::vector<PhysicsTower>::iterator towerIter = towers.begin(); towerIter != towers.end(); towerIter++){
+	double dEta = fabs(towerIter->eta() - startEta);
+	double dPhi = fabs(towerIter->phi() - startPhi);
+	if(dPhi > M_PI)
+	  dPhi = 2*M_PI - dPhi;
+	double dR = sqrt(dEta*dEta + dPhi*dPhi);
+	if(dR < _coneRadius)
+	  trialCone.addTower(*towerIter);
+      }
+      if(_iratch != 0)
+	for(std::vector<PhysicsTower>::iterator preClusterTowerIter = preClusterIter->towerList.begin();
+	    preClusterTowerIter != preClusterIter->towerList.end();
+	    preClusterTowerIter++){
+	  bool foundInTrialCone = false;
+	  for(std::vector<PhysicsTower>::iterator trialConeTowerIter = trialCone.towerList.begin();
+	      trialConeTowerIter != trialCone.towerList.end() && !foundInTrialCone;
+	      trialConeTowerIter++)
+	    if(trialConeTowerIter->isEqual(*preClusterTowerIter))
+	      foundInTrialCone = true;
+	  if(!foundInTrialCone)
+	    trialCone.addTower(*preClusterTowerIter);
+	}
+      if(nIterations <= _maxIterations){
+	double endEt  = trialCone.centroid.Et;
+	double endEta = trialCone.centroid.eta;
+	double endPhi = trialCone.centroid.phi;
+	if(endEt == startEt && endEta == startEta && endPhi == startPhi)
+	  nIterations = _maxIterations;
+	else{
+	  startEt  = endEt;
+	  startEta = endEta;
+	  startPhi = endPhi;
+	}
+      }
+    }
+//    bool foundIdentical = false;
+//    for(std::vector<Cluster>::iterator stableConeIter = stableCones.begin();
+//	stableConeIter != stableCones.end() && !foundIdentical;
+//	stableConeIter++)
+//      if(trialCone.centroid.isEqual(stableConeIter->centroid))
+//	foundIdentical = true;
+//    if(!foundIdentical)
+      stableCones.push_back(trialCone);
+  }
+  sort(stableCones.begin(),stableCones.end(),ClusterCentroidEtGreater());
+}
+
+void JetCluAlgorithm::splitAndMerge(std::vector<Cluster>& stableCones, std::vector<Cluster>& jets)
+{
+  std::vector<bool> isActive;
+  for(std::vector<Cluster>::iterator stableConeIter = stableCones.begin(); stableConeIter != stableCones.end(); stableConeIter++)
+    isActive.push_back(bool(true));
+  std::vector<bool>::iterator isActiveIter1 = isActive.begin();
+  for(std::vector<Cluster>::iterator stableConeIter1 = stableCones.begin();
+      stableConeIter1 != stableCones.end();
+      stableConeIter1++, isActiveIter1++){
+    std::vector<Cluster>::iterator stableConeIter2 = stableCones.begin();
+    std::vector<bool>::iterator isActiveIter2 = isActive.begin();
+    while(stableConeIter2 != stableConeIter1 && *isActiveIter1){
+      if(*isActiveIter2){
+	Cluster overlap;
+	for(std::vector<PhysicsTower>::iterator towerIter1 = stableConeIter1->towerList.begin();
+	    towerIter1 != stableConeIter1->towerList.end();
+	    towerIter1++)
+	  for(std::vector<PhysicsTower>::iterator towerIter2 = stableConeIter2->towerList.begin();
+	      towerIter2 != stableConeIter2->towerList.end();
+	      towerIter2++)
+	    if(towerIter1->isEqual(*towerIter2)){
+	      overlap.addTower(*towerIter1);
+	      break;
+	    }
+	if(overlap.size()){
+	  if(overlap.size() == stableConeIter2->size())
+	    *isActiveIter2 = false;
+	  else if(overlap.size() == stableConeIter1->size())
+	    *isActiveIter1 = false;
+	  else if(overlap.centroid.Et > _overlapThreshold*stableConeIter1->centroid.Et ||
+		  overlap.centroid.Et > _overlapThreshold*stableConeIter2->centroid.Et){
+	    for(std::vector<PhysicsTower>::iterator stableConeTowerIter2 = stableConeIter2->towerList.begin();
+		stableConeTowerIter2 != stableConeIter2->towerList.end();
+		stableConeTowerIter2++){
+	      bool isInOverlap = false;
+	      for(std::vector<PhysicsTower>::iterator overlapTowerIter = overlap.towerList.begin();
+		  overlapTowerIter != overlap.towerList.end() && !isInOverlap;
+		  overlapTowerIter++)
+		if(stableConeTowerIter2->isEqual(*overlapTowerIter))
+		  isInOverlap = true;
+	      if(!isInOverlap)
+		stableConeIter1->addTower(*stableConeTowerIter2);
+	    }
+	    *isActiveIter2 = false;
+	  }
+	  else{
+	    Cluster removeFromStableCone1,removeFromStableCone2,oldRemoveFromStableCone1,oldRemoveFromStableCone2;
+	    double etaStableCone1 = stableConeIter1->centroid.eta;
+	    double phiStableCone1 = stableConeIter1->centroid.phi;
+	    double etaStableCone2 = stableConeIter2->centroid.eta;
+	    double phiStableCone2 = stableConeIter2->centroid.phi;
+	    double dRstableCone1,dRstableCone2;
+	    int iterCount = 0;
+	    while(iterCount++ <= _maxIterations){
+	      oldRemoveFromStableCone1.clear();
+	      oldRemoveFromStableCone2.clear();
+	      if(iterCount > 1){
+		if(removeFromStableCone1.size()){
+		  Centroid stableConeCentroid1(stableConeIter1->centroid);
+		  Centroid removeCentroid1(removeFromStableCone1.centroid);
+		  stableConeCentroid1.subtract(removeCentroid1);
+		  etaStableCone1 = stableConeCentroid1.eta;
+		  phiStableCone1 = stableConeCentroid1.phi;
+		}
+		else{
+		  etaStableCone1 = stableConeIter1->centroid.eta;
+		  phiStableCone1 = stableConeIter1->centroid.phi;
+		}
+		if(removeFromStableCone2.size()){
+		  Centroid stableConeCentroid2(stableConeIter2->centroid);
+		  Centroid removeCentroid2(removeFromStableCone2.centroid);
+		  stableConeCentroid2.subtract(removeCentroid2);
+		  etaStableCone2 = stableConeCentroid2.eta;
+		  phiStableCone2 = stableConeCentroid2.phi;
+		}
+		else{
+		  etaStableCone2 = stableConeIter2->centroid.eta;
+		  phiStableCone2 = stableConeIter2->centroid.phi;
+		}
+		for(std::vector<PhysicsTower>::iterator removeTowerIter1 = removeFromStableCone1.towerList.begin();
+		    removeTowerIter1 != removeFromStableCone1.towerList.end();
+		    removeTowerIter1++)
+		  oldRemoveFromStableCone1.addTower(*removeTowerIter1);
+		for(std::vector<PhysicsTower>::iterator removeTowerIter2 = removeFromStableCone2.towerList.begin();
+		    removeTowerIter2 != removeFromStableCone2.towerList.end();
+		    removeTowerIter2++)
+		  oldRemoveFromStableCone2.addTower(*removeTowerIter2);
+	      }
+	      removeFromStableCone1.clear();
+	      removeFromStableCone2.clear();
+	      for(std::vector<PhysicsTower>::iterator overlapTowerIter = overlap.towerList.begin();
+		  overlapTowerIter != overlap.towerList.end();
+		  overlapTowerIter++){
+		double dEta1 = fabs(overlapTowerIter->eta() - etaStableCone1);
+		double dPhi1 = fabs(overlapTowerIter->phi() - phiStableCone1);
+		if(dPhi1 > M_PI)
+		  dPhi1 = 2*M_PI - dPhi1;
+		dRstableCone1 = dEta1*dEta1 + dPhi1*dPhi1;
+		double dEta2 = fabs(overlapTowerIter->eta() - etaStableCone2);
+		double dPhi2 = fabs(overlapTowerIter->phi() - phiStableCone2);
+		if(dPhi2 > M_PI)
+		  dPhi2 = 2*M_PI - dPhi2;
+		dRstableCone2 = dEta2*dEta2 + dPhi2*dPhi2;
+		if(dRstableCone1 < dRstableCone2)
+		  removeFromStableCone2.addTower(*overlapTowerIter);
+		else
+		  removeFromStableCone1.addTower(*overlapTowerIter);
+	      }
+	      if(iterCount > 1 &&
+		 removeFromStableCone1.size() == oldRemoveFromStableCone1.size() &&
+		 removeFromStableCone2.size() == oldRemoveFromStableCone2.size() &&
+		 (!removeFromStableCone1.size() || !removeFromStableCone2.size() ||
+		  removeFromStableCone1.centroid.isEqual(oldRemoveFromStableCone1.centroid) &&
+		  removeFromStableCone2.centroid.isEqual(oldRemoveFromStableCone2.centroid)))
+		iterCount = _maxIterations + 1;
+	    }
+	    for(std::vector<PhysicsTower>::iterator removeTowerIter1 = removeFromStableCone1.towerList.begin();
+		removeTowerIter1 != removeFromStableCone1.towerList.end();
+		removeTowerIter1++)
+	      stableConeIter1->removeTower(*removeTowerIter1);
+	    for(std::vector<PhysicsTower>::iterator removeTowerIter2 = removeFromStableCone2.towerList.begin();
+		removeTowerIter2 != removeFromStableCone2.towerList.end();
+		removeTowerIter2++)
+	      stableConeIter2->removeTower(*removeTowerIter2);
+	  }
+	  overlap.clear();
+	}
+      }
+      stableConeIter2++;
+      isActiveIter2++;
+    }
+  }
+  jets.clear();
+  std::vector<bool>::iterator isActiveIter = isActive.begin();
+  for(std::vector<Cluster>::iterator stableConeIter = stableCones.begin();
+      stableConeIter != stableCones.end();
+      stableConeIter++, isActiveIter++)
+    if(*isActiveIter)
+      jets.push_back(*stableConeIter);
+  sort(jets.begin(),jets.end(),ClusterFourVectorEtGreater());
+}
+
+void JetCluAlgorithm::run(std::vector<PhysicsTower>& towers, std::vector<Cluster>& jets)
+{
+  std::vector<Cluster> seedTowers;
+  makeSeedTowers(towers,seedTowers);
+  std::vector<Cluster> preClusters;
+  buildPreClusters(seedTowers,towers,preClusters);
+  std::vector<Cluster> stableCones;
+  findStableCones(preClusters,towers,stableCones);
+  splitAndMerge(stableCones,jets);
+}
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/LorentzVector.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/LorentzVector.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/LorentzVector.cc	(revision 11)
@@ -0,0 +1,1 @@
+#include "../interface/LorentzVector.hh"
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/MidPointAlgorithm.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/MidPointAlgorithm.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/MidPointAlgorithm.cc	(revision 11)
@@ -0,0 +1,313 @@
+#include "../interface/MidPointAlgorithm.hh"
+#include "../interface/ClusterComparisons.hh"
+#include <algorithm>
+#include <iostream>
+#include <cmath>
+
+void MidPointAlgorithm::findStableConesFromSeeds(std::vector<PhysicsTower>& towers, std::vector<Cluster>& stableCones)
+{
+  bool reduceConeSize = true;
+  for(std::vector<PhysicsTower>::iterator towerIter = towers.begin(); towerIter != towers.end(); towerIter++)
+    if(towerIter->fourVector.pt() > _seedThreshold)
+      iterateCone(towerIter->fourVector.y(),towerIter->fourVector.phi(),0,towers,stableCones,reduceConeSize);
+}
+
+void MidPointAlgorithm::findStableConesFromMidPoints(std::vector<PhysicsTower>& towers, std::vector<Cluster>& stableCones)
+{
+  // distanceOK[i-1][j] = Is distance between stableCones i and j (i>j) less than 2*_coneRadius?
+  std::vector< std::vector<bool> > distanceOK;
+  distanceOK.resize(stableCones.size() - 1);
+  for(int nCluster1 = 1; nCluster1 < stableCones.size(); nCluster1++){
+    distanceOK[nCluster1 - 1].resize(nCluster1);
+    double cluster1Rapidity = stableCones[nCluster1].fourVector.y();
+    double cluster1Phi      = stableCones[nCluster1].fourVector.phi();
+    for(int nCluster2 = 0; nCluster2 < nCluster1; nCluster2++){
+      double cluster2Rapidity = stableCones[nCluster2].fourVector.y();
+      double cluster2Phi      = stableCones[nCluster2].fourVector.phi();
+      double dRapidity = fabs(cluster1Rapidity - cluster2Rapidity);
+      double dPhi      = fabs(cluster1Phi      - cluster2Phi);
+      if(dPhi > M_PI)
+        dPhi = 2*M_PI - dPhi;
+      double dR = sqrt(dRapidity*dRapidity + dPhi*dPhi);
+      distanceOK[nCluster1 - 1][nCluster2] = dR < 2*_coneRadius;
+    }
+  }
+
+  // Find all pairs (triplets, ...) of stableCones which are less than 2*_coneRadius apart from each other.
+  std::vector< std::vector<int> > pairs(0);
+  std::vector<int> testPair(0);
+  int maxClustersInPair = _maxPairSize;
+  if(!maxClustersInPair)
+    maxClustersInPair = stableCones.size();
+  addClustersToPairs(testPair,pairs,distanceOK,maxClustersInPair);
+
+  // Loop over all combinations. Calculate MidPoint. Make midPointClusters.
+  bool reduceConeSize = false;
+  for(int iPair = 0; iPair < pairs.size(); iPair++){
+    // Calculate rapidity, phi and pT of MidPoint.
+    LorentzVector midPoint(0,0,0,0);
+    for(int iPairMember = 0; iPairMember < pairs[iPair].size(); iPairMember++)
+      midPoint.add(stableCones[pairs[iPair][iPairMember]].fourVector);
+    iterateCone(midPoint.y(),midPoint.phi(),midPoint.pt(),towers,stableCones,reduceConeSize);
+  }
+
+  //sort(stableCones.begin(),stableCones.end(),ClusterPtGreater());
+  local_sort(stableCones);  // GPS mod. to allow split-merge with various scales
+}
+
+
+void MidPointAlgorithm::iterateCone(volatile double startRapidity, volatile double startPhi, volatile double startPt,
+				    std::vector<PhysicsTower>& towers, std::vector<Cluster>& stableCones, bool reduceConeSize)
+{
+  int nIterations = 0;
+  bool keepJet = true;
+  Cluster trialCone;
+  double iterationConeRadius = _coneRadius;
+  if(reduceConeSize)
+    iterationConeRadius *= sqrt(_coneAreaFraction);
+  while(nIterations++ < _maxIterations + 1 && keepJet){
+    trialCone.clear();
+    // Find particles which should go in the cone.
+    if(nIterations == _maxIterations + 1)
+      iterationConeRadius = _coneRadius;
+    for(std::vector<PhysicsTower>::iterator towerIter = towers.begin(); towerIter != towers.end(); towerIter++){
+      double dRapidity = fabs(towerIter->fourVector.y()   - startRapidity);
+      double dPhi      = fabs(towerIter->fourVector.phi() - startPhi);
+      if(dPhi > M_PI)
+	dPhi = 2*M_PI - dPhi;
+      double dR = sqrt(dRapidity*dRapidity + dPhi*dPhi);
+      if(dR < iterationConeRadius)
+	trialCone.addTower(*towerIter);
+    }
+    if(!trialCone.size())   // Empty cone?
+      keepJet = false;
+    else{
+      if(nIterations <= _maxIterations){
+	volatile double endRapidity = trialCone.fourVector.y();
+	volatile double endPhi      = trialCone.fourVector.phi();
+	volatile double endPt       = trialCone.fourVector.pt();
+	// Do we have a stable cone?
+	if(endRapidity == startRapidity && endPhi == startPhi && endPt == startPt){
+	  // If cone size is reduced, then do one more iteration.
+	  nIterations = _maxIterations;
+	  if(!reduceConeSize)
+	    nIterations++;
+	}
+	else{
+	  // Another iteration.
+	  startRapidity = endRapidity;
+	  startPhi      = endPhi;
+	  startPt       = endPt;
+	}
+      }
+    }
+  }
+
+  if(keepJet){
+    // We have a stable cone.
+    bool identical = false;
+    for(std::vector<Cluster>::iterator stableConeIter = stableCones.begin(); stableConeIter != stableCones.end(); stableConeIter++)
+      if(trialCone.fourVector.isEqual(stableConeIter->fourVector))
+	identical = true;
+    if(!identical)
+      stableCones.push_back(trialCone);
+  }
+}
+
+void MidPointAlgorithm::addClustersToPairs(std::vector<int>& testPair, std::vector< std::vector<int> >& pairs,
+					   std::vector< std::vector<bool> >& distanceOK, int maxClustersInPair)
+{
+  // Recursively adds clusters to pairs, triplets, ... whose mid-points are then calculated.
+
+  // Find StableCone number to start with (either 0 at the beginning or last element of testPair + 1).
+  int nextClusterStart = 0;
+  if(testPair.size())
+    nextClusterStart = testPair.back() + 1;
+  for(int nextCluster = nextClusterStart; nextCluster <= distanceOK.size(); nextCluster++){
+    // Is new SeedCone less than 2*_coneRadius apart from all clusters in testPair?
+    bool addCluster = true;
+    for(int iCluster = 0; iCluster < testPair.size() && addCluster; iCluster++)
+      if(!distanceOK[nextCluster - 1][testPair[iCluster]])
+	addCluster = false;
+    if(addCluster){
+      // Add it to the testPair.
+      testPair.push_back(nextCluster);
+      // If testPair is a pair, add it to pairs.
+      if(testPair.size() > 1)
+	pairs.push_back(testPair);
+      // If not bigger than allowed, find more clusters within 2*_coneRadius.
+      if(testPair.size() < maxClustersInPair)
+	addClustersToPairs(testPair,pairs,distanceOK,maxClustersInPair);
+      // All combinations containing testPair found. Remove last element.
+      testPair.pop_back();
+    }
+  }
+}
+
+void MidPointAlgorithm::splitAndMerge(std::vector<Cluster>& stableCones, std::vector<Cluster>& jets)
+{
+  bool mergingNotFinished = true;
+  while(mergingNotFinished){
+    // Sort the stable cones (highest pt first).
+    //sort(stableCones.begin(),stableCones.end(),ClusterPtGreater());
+    local_sort(stableCones);
+
+    // Start with the highest pt cone.
+    std::vector<Cluster>::iterator stableConeIter1 = stableCones.begin();
+    if(stableConeIter1 == stableCones.end())   // Stable cone list empty?
+      mergingNotFinished = false;
+    else{
+      bool coneNotModified = true;
+      // Determine whether highest pt cone has an overlap with other stable cones.
+      std::vector<Cluster>::iterator stableConeIter2 = stableConeIter1;
+      stableConeIter2++;   // 2nd highest pt cone.
+      while(coneNotModified && stableConeIter2 != stableCones.end()){
+	// Calculate overlap of the two cones.
+	Cluster overlap;
+	for(std::vector<PhysicsTower>::iterator towerIter1 = stableConeIter1->towerList.begin();
+	    towerIter1 != stableConeIter1->towerList.end();
+	    towerIter1++){
+	  bool isInCone2 = false;
+	  for(std::vector<PhysicsTower>::iterator towerIter2 = stableConeIter2->towerList.begin();
+	      towerIter2 != stableConeIter2->towerList.end();
+	      towerIter2++)
+	    if(towerIter1->isEqual(*towerIter2))
+	      isInCone2 = true;
+	  if(isInCone2)
+	    overlap.addTower(*towerIter1);
+	}
+	if(overlap.size()){   // non-empty overlap
+	  coneNotModified = false;
+          // GPS mod to allow various scale choices in split merge --------
+          double overlap_scale, jet2_scale;
+          switch(_smScale) {
+          case SM_pt:
+            overlap_scale = overlap.fourVector.pt();
+            jet2_scale    = stableConeIter2->fourVector.pt();
+            break;
+          case SM_Et:
+            overlap_scale = overlap.fourVector.Et();
+            jet2_scale    = stableConeIter2->fourVector.Et();
+            break;
+          case SM_mt:
+            overlap_scale = overlap.fourVector.mt();
+            jet2_scale    = stableConeIter2->fourVector.mt();
+            break;
+          case SM_pttilde:
+            overlap_scale = overlap.pt_tilde;
+            jet2_scale    = stableConeIter2->pt_tilde;
+            break;
+          default:
+            std::cerr << "Unrecognized value for _smScale: " 
+                      << _smScale << std::endl;
+            exit(-1);
+          }
+	  if(overlap_scale >= _overlapThreshold*jet2_scale){
+          // end of GPS modification ---------------------------
+          //if(overlap.fourVector.pt() >= _overlapThreshold*stableConeIter2->fourVector.pt()){
+	    // Merge the two cones.
+	    for(std::vector<PhysicsTower>::iterator towerIter2 = stableConeIter2->towerList.begin();
+		towerIter2 != stableConeIter2->towerList.end();
+		towerIter2++){
+	      bool isInOverlap = false;
+	      for(std::vector<PhysicsTower>::iterator overlapTowerIter = overlap.towerList.begin();
+		  overlapTowerIter != overlap.towerList.end();
+		  overlapTowerIter++)
+		if(towerIter2->isEqual(*overlapTowerIter))
+		  isInOverlap = true;
+	      if(!isInOverlap)
+		stableConeIter1->addTower(*towerIter2);
+	    }
+	    // Remove the second cone.
+	    stableCones.erase(stableConeIter2);
+	  }
+	  else{
+	    // Separate the two cones.
+	    // Which particle goes where?
+	    std::vector<PhysicsTower> removeFromCone1,removeFromCone2;
+	    for(std::vector<PhysicsTower>::iterator towerIter = overlap.towerList.begin();
+		towerIter != overlap.towerList.end();
+		towerIter++){
+	      double towerRapidity = towerIter->fourVector.y();
+	      double towerPhi      = towerIter->fourVector.phi();
+	      // Calculate distance from cone 1.
+	      double dRapidity1 = fabs(towerRapidity - stableConeIter1->fourVector.y());
+	      double dPhi1      = fabs(towerPhi      - stableConeIter1->fourVector.phi());
+	      if(dPhi1 > M_PI)
+		dPhi1 = 2*M_PI - dPhi1;
+	      double dRJet1 = sqrt(dRapidity1*dRapidity1 + dPhi1*dPhi1);
+	      // Calculate distance from cone 2.
+	      double dRapidity2 = fabs(towerRapidity - stableConeIter2->fourVector.y());
+	      double dPhi2      = fabs(towerPhi      - stableConeIter2->fourVector.phi());
+	      if(dPhi2 > M_PI)
+		dPhi2 = 2*M_PI - dPhi2;
+	      double dRJet2 = sqrt(dRapidity2*dRapidity2 + dPhi2*dPhi2);
+	      if(dRJet1 < dRJet2)
+		// Particle is closer to cone 1. To be removed from cone 2.
+		removeFromCone2.push_back(*towerIter);
+	      else
+		// Particle is closer to cone 2. To be removed from cone 1.
+		removeFromCone1.push_back(*towerIter);
+	    }
+	    // Remove particles in the overlap region from the cones to which they have the larger distance.
+	    for(std::vector<PhysicsTower>::iterator towerIter = removeFromCone1.begin();
+		towerIter != removeFromCone1.end();
+		towerIter++)
+	      stableConeIter1->removeTower(*towerIter);
+	    for(std::vector<PhysicsTower>::iterator towerIter = removeFromCone2.begin();
+		towerIter != removeFromCone2.end();
+		towerIter++)
+	      stableConeIter2->removeTower(*towerIter);
+	  }
+	}
+	stableConeIter2++;
+      }
+      if(coneNotModified){
+	// Cone 1 has no overlap with any of the other cones and can become a jet.
+	jets.push_back(*stableConeIter1);
+	stableCones.erase(stableConeIter1);
+      }
+    }
+  }
+
+  //sort(jets.begin(),jets.end(),ClusterPtGreater());
+  local_sort(jets); // GPS mod. to allow split-merge with various scales
+}
+
+
+
+void MidPointAlgorithm::local_sort(std::vector<Cluster>& clusters) {
+  switch(_smScale) {
+  case SM_pt:
+    sort(clusters.begin(),clusters.end(),ClusterPtGreater());
+    break;
+  case SM_Et:
+    sort(clusters.begin(),clusters.end(),ClusterFourVectorEtGreater());
+    break;
+  case SM_mt:
+    sort(clusters.begin(),clusters.end(),ClusterMtGreater());
+    break;
+  case SM_pttilde:
+    sort(clusters.begin(),clusters.end(),ClusterPtTildeGreater());
+    break;
+  default:
+    std::cerr << "Unrecognized value for _smScale: " << _smScale << std::endl;
+    exit(-1);
+  }
+}
+
+
+
+void MidPointAlgorithm::run(std::vector<PhysicsTower>& towers, std::vector<Cluster>& jets)
+{
+  std::vector<Cluster> stableCones;
+  findStableConesFromSeeds(towers,stableCones);
+  // GPS addition to prevent crashes if no stable cones
+  // are found (e.g. all particles below seed threshold)
+  if (stableCones.size() > 0) {
+    findStableConesFromMidPoints(towers,stableCones);
+    splitAndMerge(stableCones,jets);
+  }
+}
+
+
Index: /trunk/Utilities/Fastjet/plugins/CDFCones/src/PhysicsTower.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/CDFCones/src/PhysicsTower.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/CDFCones/src/PhysicsTower.cc	(revision 11)
@@ -0,0 +1,1 @@
+#include "../interface/PhysicsTower.hh"
Index: /trunk/Utilities/Fastjet/plugins/SISCone/SISConePlugin.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/SISConePlugin.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/SISConePlugin.cc	(revision 11)
@@ -0,0 +1,206 @@
+
+// fastjet stuff
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence.hh"
+#include "SISConePlugin.hh"
+
+// scones stuff
+#include "interface/momentum.h"
+#include "interface/siscone.h"
+
+// other stuff
+#include<sstream>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+using namespace siscone;
+
+// the static objects
+auto_ptr<SISConePlugin     > SISConePlugin::stored_plugin    ;
+auto_ptr<vector<PseudoJet> > SISConePlugin::stored_particles ;
+auto_ptr<Csiscone          > SISConePlugin::stored_siscone   ;
+
+string SISConePlugin::description () const {
+  ostringstream desc;
+  
+  const string on = "on";
+  const string off = "off";
+
+  string sm_scale_string = "split-merge uses " + 
+    split_merge_scale_name(Esplit_merge_scale(split_merge_scale()));
+
+  desc << "SISCone jet algorithm with " ;
+  desc << "cone_radius = "       << cone_radius        () << ", ";
+  desc << "overlap_threshold = " << overlap_threshold  () << ", ";
+  desc << "n_pass_max = "        << n_pass_max         () << ", ";
+  desc << "protojet_ptmin = "    << protojet_ptmin()      << ", ";
+  desc <<  sm_scale_string                                << ", ";
+  desc << "caching turned "      << (caching() ? on : off);
+  desc << ", SM stop scale = "     << _split_merge_stopping_scale;
+
+
+  // create a fake siscone object so that we can find out more about it
+  Csiscone siscone;
+  if (siscone.merge_identical_protocones) {
+    desc << ", and (IR unsafe) merge_indentical_protocones=true" ;
+  }
+
+  desc << ", SISCone code v" << siscone_version();
+
+  return desc.str();
+}
+
+
+/// shortcut for converting siscone Cmomentum into PseudoJet
+template<> PseudoJet::PseudoJet(const Cmomentum & four_vector) {
+  (*this) = PseudoJet(four_vector.px,four_vector.py,four_vector.pz,
+                      four_vector.E);
+}
+
+
+void SISConePlugin::run_clustering(ClusterSequence & clust_seq) const {
+
+
+  Csiscone * siscone;
+  Csiscone   local_siscone;
+
+  unsigned n = clust_seq.jets().size();
+
+  bool new_siscone = true; // by default we'll be running it
+
+  if (caching()) {
+
+    // Establish if we have a cached run with the same R, npass and
+    // particles. If not then do any tidying up / reallocation that's
+    // necessary for the next round of caching, otherwise just set
+    // relevant pointers so that we can reuse and old run.
+    if (stored_siscone.get() != 0) {
+      new_siscone = !(stored_plugin->cone_radius()   == cone_radius()
+                      && stored_plugin->n_pass_max() == n_pass_max()  
+                      && stored_particles->size()    == n);
+      if (!new_siscone) {
+        for(unsigned i = 0; i < n; i++) {
+          // only check momentum because indices will be correctly dealt
+          // with anyway when extracting the clustering order.
+          new_siscone |= !have_same_momentum(clust_seq.jets()[i], 
+                                             (*stored_particles)[i]);
+        }
+      }
+    } 
+      
+    // allocate the new siscone, etc., if need be
+    if (new_siscone) {
+      stored_siscone  .reset( new Csiscone                           );
+      stored_particles.reset( new vector<PseudoJet>(clust_seq.jets()));
+      stored_plugin   .reset( new SISConePlugin(*this)               );
+    }
+
+    siscone = stored_siscone.get();
+  } else {
+    siscone = &local_siscone;
+  }
+
+  // make sure stopping scale is set in siscone
+  siscone->SM_var2_hardest_cut_off = _split_merge_stopping_scale*_split_merge_stopping_scale;
+  // when running with ghosts for passive areas, do not put the
+  // ghosts into the stable-cone search (not relevant)
+  siscone->stable_cone_soft_pt2_cutoff = ghost_separation_scale()
+                                         * ghost_separation_scale();
+
+  if (new_siscone) {
+    // transfer fastjet initial particles into the siscone type
+    vector<Cmomentum> siscone_momenta(n);
+    for(unsigned i = 0; i < n; i++) {
+      const PseudoJet & p = clust_seq.jets()[i]; // shorthand
+      siscone_momenta[i] = Cmomentum(p.px(), p.py(), p.pz(), p.E());
+    }
+    
+    // run the jet finding
+    //cout << "plg sms: " << split_merge_scale() << endl;
+    siscone->compute_jets(siscone_momenta, cone_radius(), overlap_threshold(),
+                          n_pass_max(), protojet_or_ghost_ptmin(), 
+                          Esplit_merge_scale(split_merge_scale()));
+  } else {
+    // just run the overlap part of the jets.
+    //cout << "plg rcmp sms: " << split_merge_scale() << endl;
+    siscone->recompute_jets(overlap_threshold(), protojet_or_ghost_ptmin(), 
+                            Esplit_merge_scale(split_merge_scale()));
+  }
+
+  // extract the jets [in reverse order -- to get nice ordering in pt at end]
+  int njet = siscone->jets.size();
+
+  for (int ijet = njet-1; ijet >= 0; ijet--) {
+    const Cjet & jet = siscone->jets[ijet]; // shorthand
+    
+    // Successively merge the particles that make up the cone jet
+    // until we have all particles in it.  Start off with the zeroth
+    // particle.
+    int jet_k = jet.contents[0];
+    for (unsigned ipart = 1; ipart < jet.contents.size(); ipart++) {
+      // take the last result of the merge
+      int jet_i = jet_k;
+      // and the next element of the jet
+      int jet_j = jet.contents[ipart];
+      // and merge them (with a fake dij)
+      double dij = 0.0;
+
+      // create the new jet by hand so that we can adjust its user index
+      PseudoJet newjet = clust_seq.jets()[jet_i] + clust_seq.jets()[jet_j];
+
+      // set the user index to be the pass in which the jet was discovered
+      newjet.set_user_index(jet.pass);
+        
+      clust_seq.plugin_record_ij_recombination(jet_i, jet_j, dij, newjet, jet_k);
+    }
+    // we have merged all the jet's particles into a single object, so now
+    // "declare" it to be a beam (inclusive) jet.
+    // [NB: put a sensible looking d_iB just to be nice...]
+    double d_iB = clust_seq.jets()[jet_k].perp2();
+    clust_seq.plugin_record_iB_recombination(jet_k, d_iB);
+  }
+
+  // now copy the list of protocones into an "extras" objects
+  SISConeExtras * extras = new SISConeExtras;
+  for (unsigned ipass = 0; ipass < siscone->protocones_list.size(); ipass++) {
+    for (unsigned ipc = 0; ipc < siscone->protocones_list[ipass].size(); ipc++) {
+      double rap = siscone->protocones_list[ipass][ipc].eta;
+      double phi = siscone->protocones_list[ipass][ipc].phi;
+      PseudoJet protocone(cos(phi),sin(phi),sinh(rap),cosh(rap));
+      //PseudoJet protocone(siscone->protocones_list[ipass][ipc]);
+      protocone.set_user_index(ipass);
+      extras->_protocones.push_back(protocone);
+    }
+  }
+  extras->_most_ambiguous_split = siscone->most_ambiguous_split;
+
+  // tell it what the jet definition was
+  extras->_jet_def_plugin = this;
+
+  // give the extras object to the cluster sequence.
+  clust_seq.plugin_associate_extras(auto_ptr<ClusterSequence::Extras>(extras));
+}
+
+
+/// 
+string SISConeExtras::description() const {
+  ostringstream ostr;
+  ostr << "This SISCone clustering found " << protocones().size() 
+       << " stable protocones";
+  return ostr.str();
+}
+
+// OBSOLETE CODE  
+//// temporary, for dealing with warnings...
+//if (siscone.n_warnings > 0) {
+//  // print the event (very dirty...)
+//  cout.precision(14);
+//  cout << "Culprit event is:" << endl;
+//  for (int i = 0; i < n; i++) {
+//    const PseudoJet & p = clust_seq.jets()[i]; // shorthand
+//    cout << p.px() << " " << p.py() << " " << p.pz() << " " << p.E() << endl;
+//  }
+//}
+
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
Index: /trunk/Utilities/Fastjet/plugins/SISCone/SISConePlugin.hh
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/SISConePlugin.hh	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/SISConePlugin.hh	(revision 11)
@@ -0,0 +1,273 @@
+#ifndef __SISCONEPLUGIN_HH__
+#define __SISCONEPLUGIN_HH__
+
+#include "Utilities/Fastjet/include/fastjet/JetDefinition.hh"
+#include "Utilities/Fastjet/include/fastjet/ClusterSequence.hh" // needed for the extras we define
+#include <vector>
+#include <memory>
+#include <cmath>
+
+// put a forward declaration to the Csiscone class to avoid having to
+// include the siscone headers here
+namespace siscone {
+  class Csiscone;
+}
+
+// questionable whether this should be in fastjet namespace or not...
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+// another forward declaration to reduce includes
+class PseudoJet;
+
+//----------------------------------------------------------------------
+//
+/// SISConePlugin is a plugin for fastjet (v2.1 upwards) that provides
+/// an interface to the seedless infrared safe cone jet finder by
+/// Gregory Soyez and Gavin Salam.
+///
+/// As of 2006-12-26, this plugin is beta, as is the SISCone code
+/// itself.
+///
+/// SISCone uses geometrical techniques to exhaustively consider all
+/// possible distinct cones. It then finds out which ones are stable
+/// and sends the result to the Tevatron Run-II type split-merge
+/// procedure for overlapping cones.
+///
+/// Four parameters govern the "physics" of the algorithm:
+///
+///  - the cone_radius (this should be self-explanatory!)
+///
+///  - the overlap_threshold is the parameter which dictates how much
+///    two jets must overlap (pt_overlap/min(pt1,pt2)) if they are to be 
+///    merged
+///
+///  - Not all particles are in stable cones in the first round of
+///    searching for stable cones; one can therefore optionally have the
+///    the jet finder carry out additional passes of searching for
+///    stable cones among particles that were in no stable cone in
+///    previous passes --- the maximum number of passes carried out is
+///    n_pass_max. If this is zero then additional passes are carried
+///    out until no new stable cones are found.
+///
+///  - Protojet ptmin: protojets that are below this ptmin
+///    (default = 0) are discarded before each iteration of the
+///    split-merge loop.
+///
+/// One parameter governs some internal algorithmic shortcuts: 
+///
+/// - if "caching" is turned on then the last event clustered by
+///   siscone is stored -- if the current event is identical and the
+///   cone_radius and n_pass_mass are identical, then the only part of
+///   the clustering that needs to be rerun is the split-merge part,
+///   leading to significant speed gains; there is a small (O(N) storage
+///   and speed) penalty for caching, so it should be kept off
+///   (default) if only a single overlap_threshold is used.
+///
+/// The final jets can be accessed by requestion the
+/// inclusive_jets(...) from the ClusterSequence object. Note that
+/// these PseudoJets have their user_index() set to the index of the
+/// pass in which they were found (first pass = 0). NB: This does not
+/// currently work for jets that consist of a single particle.
+///
+/// For further information on the details of the algorithm see the
+/// SISCone paper; for documentation about the implementation, see the
+/// siscone/doc/html/index.html file.
+//
+class SISConePlugin : public JetDefinition::Plugin {
+public:
+
+  /// enum for the different split-merge scale choices;
+  /// Note that order _must_ be the same as in siscone
+  enum SplitMergeScale {SM_pt,     ///< transverse momentum (E-scheme), IR unsafe
+                        SM_Et,     ///< transverse energy (E-scheme), not long. boost invariant
+                                   ///< original run-II choice [may not be implemented]
+                        SM_mt,     ///< transverse mass (E-scheme), IR safe except
+                                   ///< in decays of two identical narrow heavy particles
+                        SM_pttilde ///< pt-scheme pt = \sum_{i in jet} |p_{ti}|, should
+                                   ///< be IR safe in all cases
+  };
+
+
+  /// Constructor for the SISCone Plugin class.  
+  ///
+  /// Note: though the default value here for the overlap_threshold is
+  /// 0.5 (for backwards compatibility), there is a strong
+  /// recommendation to use a higher value, e.g. 0.75, especially in
+  /// environments with a substantial amount of underlying event or
+  /// pileup.
+  SISConePlugin (double cone_radius,
+                 double overlap_threshold = 0.5,
+                 int    n_pass_max = 0,
+                 double protojet_ptmin = 0.0, 
+                 bool   caching = false,
+                 SplitMergeScale  split_merge_scale = SM_pttilde,
+                 double split_merge_stopping_scale = 0.0) :
+    _cone_radius           (cone_radius       ),
+    _overlap_threshold     (overlap_threshold ),
+    _n_pass_max            (n_pass_max ), 
+    _protojet_ptmin        (protojet_ptmin),
+    _caching               (caching),             
+    _split_merge_scale     (split_merge_scale),
+    _split_merge_stopping_scale (split_merge_stopping_scale),
+    _ghost_sep_scale       (0.0) {}
+
+  /// Backwards compatible constructor for the SISCone Plugin class
+  SISConePlugin (double cone_radius,
+                 double overlap_threshold,
+                 int    n_pass_max,
+                 double protojet_ptmin, 
+                 bool   caching ,
+                 bool   split_merge_on_transverse_mass) :
+    _cone_radius           (cone_radius       ),
+    _overlap_threshold     (overlap_threshold ),
+    _n_pass_max            (n_pass_max ), 
+    _protojet_ptmin        (protojet_ptmin),
+    _caching               (caching),             
+    _split_merge_scale     (split_merge_on_transverse_mass ? SM_mt : SM_pttilde),
+    _ghost_sep_scale       (0.0)  {}
+  
+  /// backwards compatible constructor for the SISCone Plugin class
+  /// (avoid using this in future).
+  SISConePlugin (double cone_radius,
+                 double overlap_threshold,
+                 int    n_pass_max,
+                 bool   caching ) :
+    _cone_radius           (cone_radius       ),
+    _overlap_threshold     (overlap_threshold ),
+    _n_pass_max            (n_pass_max ), 
+    _protojet_ptmin        (0.0),
+    _caching               (caching),
+    _split_merge_scale     (SM_mt),
+    _ghost_sep_scale       (0.0) {}
+
+  /// copy constructor
+  SISConePlugin (const SISConePlugin & plugin) {
+    *this = plugin;
+  }
+
+  /// the cone radius
+  double cone_radius        () const {return _cone_radius        ;}
+
+  /// Fraction of overlap energy in a jet above which jets are merged
+  /// and below which jets are split.
+  double overlap_threshold  () const {return _overlap_threshold  ;}
+
+  /// the maximum number of passes of stable-cone searching (<=0 is same
+  /// as infinity).
+  int n_pass_max  () const {return _n_pass_max  ;}
+
+  /// minimum pt for a protojet to be considered in the split-merge step
+  /// of the algorithm
+  double protojet_ptmin  () const {return _protojet_ptmin  ;}
+
+  /// return the scale to be passed to SISCone as the protojet_ptmin
+  /// -- if we have a ghost separation scale that is above the
+  /// protojet_ptmin, then the ghost_separation_scale becomes the
+  /// relevant one to use here
+  double protojet_or_ghost_ptmin  () const {return std::max(_protojet_ptmin,
+                                                            _ghost_sep_scale);}
+
+  /// indicates scale used in split-merge
+  SplitMergeScale split_merge_scale() const {return _split_merge_scale;}
+  /// sets scale used in split-merge
+  void set_split_merge_scale(SplitMergeScale sms) {_split_merge_scale = sms;}
+
+  /// indicates whether the split-merge orders on transverse mass or not.
+  /// retained for backwards compatibility with 2.1.0b3
+  bool split_merge_on_transverse_mass() const {return _split_merge_scale == SM_mt ;}
+  void set_split_merge_on_transverse_mass(bool val) {
+    _split_merge_scale = val  ? SM_mt : SM_pt;}
+
+  /// set the "split_merge_stopping_scale": if the scale variable for
+  /// all protojets is below this, then stop the split-merge procedure
+  /// and keep only those jets found so far. This is useful in
+  /// determination of areas of hard jets because it can be used to
+  /// avoid running the split-merging on the pure ghost-part of the
+  /// event.
+  void set_split_merge_stopping_scale(double scale) {
+    _split_merge_stopping_scale = scale;}
+
+  /// return the value of the split_merge_stopping_scale (see
+  /// set_split_merge_stopping_scale(...) for description)
+  double split_merge_stopping_scale() {return _split_merge_stopping_scale;}
+
+  /// indicates whether caching is turned on or not.
+  bool caching() const {return _caching ;}
+
+  // the things that are required by base class
+  virtual std::string description () const;
+  virtual void run_clustering(ClusterSequence &) const;
+  /// the plugin mechanism's standard way of accessing the jet radius
+  virtual double R() const {return cone_radius();}
+
+  /// return true since there is specific support for the measurement
+  /// of passive areas, in the sense that areas determined from all
+  /// particles below the ghost separation scale will be a passive
+  /// area. 
+  virtual bool supports_ghosted_passive_areas() const {return true;}
+  
+  /// set the ghost separation scale for passive area determinations
+  /// _just_ in the next run (strictly speaking that makes the routine
+  /// a non const, so related internal info must be stored as a mutable)
+  virtual void set_ghost_separation_scale(double scale) const {
+    _ghost_sep_scale = scale;
+  }
+
+  virtual double ghost_separation_scale() const {return _ghost_sep_scale;}
+
+private:
+  double _cone_radius, _overlap_threshold;
+  int    _n_pass_max;
+  double _protojet_ptmin;
+  bool   _caching;//, _split_merge_on_transverse_mass;
+  SplitMergeScale _split_merge_scale;
+  double _split_merge_stopping_scale;
+
+  mutable double _ghost_sep_scale;
+
+  // variables for caching the results and the input
+  static std::auto_ptr<SISConePlugin          > stored_plugin;
+  static std::auto_ptr<std::vector<PseudoJet> > stored_particles;
+  static std::auto_ptr<siscone::Csiscone      > stored_siscone;
+
+};
+
+
+//======================================================================
+/// Class that provides extra information about a SISCone clustering
+class SISConeExtras : public ClusterSequence::Extras {
+public:
+  /// returns a reference to the vector of stable cones (aka protocones)
+  const std::vector<PseudoJet> & stable_cones() const {return _protocones;}
+
+  /// an old name for getting the vector of stable cones (aka protocones)
+  const std::vector<PseudoJet> & protocones() const {return _protocones;}
+
+
+  /// access to the siscone jet def plugin (more convenient than
+  /// getting it from the original jet definition, because here it's
+  /// directly of the right type (rather than the base type)
+  const SISConePlugin * jet_def_plugin() const {return _jet_def_plugin;}
+
+  /// return a brief summary of the contents of the extras object
+  /// (specifically, the number of protocones.
+  std::string description() const;
+
+  /// return the smallest difference in squared distance encountered
+  /// during splitting between a particle and two overlapping
+  /// protojets.
+  inline double most_ambiguous_split() const {return _most_ambiguous_split;}
+
+private:
+  std::vector<PseudoJet> _protocones;
+  const SISConePlugin * _jet_def_plugin;
+  double                _most_ambiguous_split;
+  // let us be written to by SISConePlugin
+  friend class SISConePlugin;
+};
+
+
+FASTJET_END_NAMESPACE        // defined in fastjet/internal/base.hh
+
+#endif // __SISCONEPLUGIN_HH__
+
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/area.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/area.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/area.h	(revision 11)
@@ -0,0 +1,140 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: area.h                                                              //
+// Description: header file for the computation of jet area                  //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:11 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __SISCONE_AREA_H__
+#define __SISCONE_AREA_H__
+
+#include "../interface/momentum.h"
+#include "../interface/siscone.h"
+
+namespace siscone{
+
+/**
+ * \class Cjet_area
+ * real Jet information, including its area(s)
+ *
+ * This class contains information for one single jet. 
+ * That is, first, its momentum carrying information
+ * about its centre and pT, and second, its particle
+ * contents.
+ * Compared to the Cjet class, it also includes the 
+ * passive and active areas of the jet computed using 
+ * the Carea class.
+ */
+class Cjet_area : public Cjet{
+ public:
+  /// default ctor
+  Cjet_area();
+
+  /// jet-initialised ctor
+  Cjet_area(Cjet &j);
+
+  /// default dtor
+  ~Cjet_area();
+
+  // area information
+  double passive_area;   ///< passive area
+  double active_area;    ///< active area
+};
+
+/**
+ * \class Csiscone_area
+ * class for the computation of jet areas.
+ * 
+ * This is the class user should use whenever you want to compute
+ * the jet area (passive and active). .
+ * It uses the SISCone algorithm to perform the jet analysis.
+ */
+class Carea : public Csiscone{
+ public:
+  /// default ctor
+  Carea();
+
+  /// default dtor
+  ~Carea();
+
+  /**
+   * compute the jet areas from a given particle set.
+   * The parameters of this method are the ones which control the jet clustering alghorithn.
+   * Note that the pt_min is not allowed here soince the jet-area determination involves soft 
+   * particles/jets and thus is used internally.
+   * \param _particles   list of particles
+   * \param _radius      cone radius
+   * \param _f           shared energy threshold for splitting&merging
+   * \param _n_pass_max  maximum number of passes (0=full search, the default)
+   * \param _split_merge_scale    the scale choice for the split-merge procedure
+   *        NOTE: SM_pt leads to IR unsafety for some events with momentum conservation. 
+   *              SM_Et is IR safe but not boost invariant and not implemented(!)
+   *              SM_mt is IR safe for hadronic events, but not for decays of two 
+   *                    back-to-back particles of identical mass
+   *              SM_pttilde  
+   *                    is always IR safe, and also boost invariant (default)
+   * \param _hard_only  when this is set on, only hard jets are computed
+   *                    and not the purely ghosted jets (default: false)
+   * \return the jets together with their areas
+   */
+  int compute_areas(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+		    int _n_pass_max=0, Esplit_merge_scale _split_merge_scale=SM_pttilde,
+		    bool _hard_only=false);
+
+  /**
+   * compute the jet active areas from a given particle set.
+   * The parameters of this method are the ones which control the jet clustering alghorithn.
+   * Note that the pt_min is not allowed here soince the jet-area determination involves soft 
+   * particles/jets and thus is used internally.
+   * See compute_areas for paramters definition.
+   * \return the jets together with their active areas
+   */
+  int compute_active_areas(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+			   int _n_pass_max=0, Esplit_merge_scale _split_merge_scale=SM_pttilde,
+			   bool _hard_only=false);
+
+  /**
+   * compute the jet passive areas from a given particle set.
+   * The parameters of this method are the ones which control the jet clustering alghorithn.
+   * Note that the pt_min is not allowed here soince the jet-area determination involves soft 
+   * particles/jets and thus is used internally.
+   * See compute_areas for paramters definition.
+   * \return the jets together with their passive areas
+   */
+  int compute_passive_areas(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+			    int _n_pass_max=0, Esplit_merge_scale _split_merge_scale=SM_pttilde);
+
+  int grid_size;        ///< size of the grid we add soft particles on (N_soft=(grid_size^2))
+  double grid_eta_max;  ///< maximal value of eta we add soft particles on
+  double grid_shift;    ///< fractional (random) displacement of the points om the grid
+
+  double pt_soft;       ///< pt of the soft particles added
+  double pt_shift;      ///< amplitude of the pt random shift
+  double pt_soft_min;   ///< pt_min used in SM to compute passive areas
+
+  /// jets with their areas
+  std::vector<Cjet_area> jet_areas;
+};
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/circulator.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/circulator.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/circulator.h	(revision 11)
@@ -0,0 +1,71 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: circulator.h                                                        //
+// Description: header file for circulator (circulator class)                //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:11 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __CIRCULATOR_H__
+#define __CIRCULATOR_H__
+
+namespace siscone{
+
+/// a circulator that is foreseen to take as template member either a
+/// pointer or an iterator;
+template<class T> class circulator { 
+
+public:
+  inline circulator(T here, T begin, T end) : m_here(here), m_begin(begin), m_end(end) {}
+
+  inline circulator(const circulator<T> & other) : m_here(other.m_here), m_begin(other.m_begin), m_end(other.m_end) {}
+
+  /// set just the position without resetting the begin and end elements
+  void set_position(const circulator<T> & other) {m_here = other.m_here;}
+  void set_position(T pointer) {m_here = pointer;}
+
+  T operator()() {return m_here;}
+
+  inline circulator<T> & operator++() { 
+    ++m_here; 
+    if (m_here == m_end) m_here = m_begin;
+    return *this;
+  }
+
+  inline circulator<T> & operator--() { 
+    if (m_here == m_begin) m_here = m_end;
+    --m_here; 
+    return *this;
+  }
+  
+  /// NB: for efficiency, this checks only the here element
+  bool operator==(const circulator & other) const {return m_here == other.m_here;}
+  /// NB: for efficiency, this checks only the here element
+  bool operator!=(const circulator & other) const {return m_here != other.m_here;}
+
+private:
+  T  m_here, m_begin, m_end;
+};
+
+}
+
+#endif // __CIRCULATOR_H__
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/config.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/config.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/config.h	(revision 11)
@@ -0,0 +1,59 @@
+/* siscone/config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "siscone"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "SISCone"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "SISCone 1.3.3"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "siscone"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.3.3"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.3.3"
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/defines.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/defines.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/defines.h	(revision 11)
@@ -0,0 +1,128 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: defines.h                                                           //
+// Description: header file for generic parameters definitions               //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:11 $//
+///////////////////////////////////////////////////////////////////////////////
+
+//! \file defines.h
+#ifndef __DEFINES_H__
+#define __DEFINES_H__
+
+/// program name
+// we get "SISCone" by calling
+//  siscone::siscone_package_name
+// defined in siscone.h
+// Otherwise, config.h
+// It is also defined as "PACKAGE_NAME" in config.h but this method 
+// might lead to conflicts
+//#define PROGRAM   PACKAGE_NAME 
+
+// program version
+// we get it from
+//   siscone::siscone_version
+// defined in siscone.h
+// It is also defined as "VERSION" in config.h but this method 
+// might lead to conflicts
+
+/// perform final stability check using the quadtree
+/// With the following define enabled, the final check for stability
+/// is performed using the quadtree rather than the explicit list of 
+/// particles (see Cstable_cone::proceed_with_stability())
+//#define USE_QUADTREE_FOR_STABILITY_TEST
+
+
+/// threshold for recomoutation of the cone (see Cstable_cones::update_cone())
+/// When traversing cone candidates along the angular ordering,
+/// the momentum of the protojet candidate is computed incrementally
+/// from the particles that enter and leave the cone.
+/// When the cumulative change in "|px|+|py|" exceeds the cone "|px|+|py|"
+/// we explicitely recompute the cone contents
+#define PT_TSHOLD 1000.0
+
+
+/// The following parameter controls collinear safety. For the set of 
+/// particles used in the search of stable cones, we gather particles
+/// if their distance in eta and phi is smaller than EPSILON_COLLINEAR.
+///
+/// NB: for things to behave sensibly one requires 
+///        1e-15 << EPSILON_COCIRCULAR << EPSILON_COLLINEAR << 1
+///
+/// among the scales that appear in practice (e.g. in deciding to use
+/// special strategies), we have EPSILON_COLLINEAR, EPSILON_COCIRCULAR,
+/// sqrt(EPSILON_COCIRCULAR) and EPSILON_COLLINEAR / EPSILON_COCIRCULAR.
+///
+#define EPSILON_COLLINEAR 1e-8
+
+
+/// The following parameter controls cocircular situations.
+/// When consecutive particles in the ordered vicinity list are separated
+/// (in angle) by less that that limit, we consider that we face a situation
+/// of cocircularity.
+#define EPSILON_COCIRCULAR 1e-12
+
+
+/// The following define enables you to allow for identical protocones
+/// to be merged automatically after each split-merge step before
+/// anything else happens. Whether this happens depends on teh value
+/// of the merge_identical_protocones flag in Csplit_merge.
+///
+/// It we allow such a merging and define allow 
+/// MERGE_IDENTICAL_PROTOCONES_DEFAULT_TRUE then the
+/// 'merge_identical_protocones' flag in Csplit_merge to be set to
+/// 'true'. It may be manually reset to false in which case the
+/// merging of identical protocones (protojets) will be turned off.
+///
+/// Note that this merging identical protocones makes the algorithm
+/// infrared-unsafe, so it should be disabled except for testing
+/// purposes.
+//#define ALLOW_MERGE_IDENTICAL_PROTOCONES
+//#define MERGE_IDENTICAL_PROTOCONES_DEFAULT_TRUE
+
+
+/// if EPSILON_SPLITMERGE is defined then, during the split-merge
+/// step, when two jets are found with PTs that are identical to
+/// within a relative difference of EPSILON_SPLITMERGE they are
+/// compared element-by-element to see where the differences are, and
+/// one then uses pt1^2-pt2^2 = (pt1-pt2).(pt1+pt2) as an estimator of
+/// which is harder. NB: in unfortunate cases, this can take the split
+/// merge step up to N n * ln N time, though on normal events there
+/// don't seem to have been any major problems yet.
+#define EPSILON_SPLITMERGE 1e-12
+
+/// definition of 2*M_PI which is useful a bit everyhere!
+const double twopi = 6.283185307179586476925286766559005768394;
+
+/// debugging information
+//#define DEBUG_STABLE_CONES   ///< debug messages in stable cones search (not implemented yet)
+//#define DEBUG_SPLIT_MERGE    ///< debug messages in split-merge
+//#define DEBUG                ///< all debug messages !
+
+// in case all debug massages allowed, allow them in practice !
+#ifdef DEBUG
+#define DEBUG_STABLE_CONES
+#define DEBUG_SPLIT_MERGE
+#endif
+
+#endif  //  __DEFINES_H__
+
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/geom_2d.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/geom_2d.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/geom_2d.h	(revision 11)
@@ -0,0 +1,179 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: geom_2d.h                                                           //
+// Description: header file for two-dimensional geometry tools               //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:11 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __GEOM_2D_H__
+#define __GEOM_2D_H__
+
+#include <iostream>
+#include <math.h>
+#include "../interface/defines.h"
+
+#ifndef M_PI
+#define M_PI 3.141592653589793238462643383279502884197
+#endif
+
+namespace siscone{
+
+/// return a result that corresponds to phi, but in the
+/// range (-pi..pi]; the result is only correct if -3pi < phi <= 3pi
+inline double phi_in_range(double phi) {
+  if      (phi <= -M_PI) phi += twopi;
+  else if (phi >   M_PI) phi -= twopi;
+  return phi;
+}
+
+/// return the difference between the two phi values, 
+/// placed in the correct range (-pi..pi], , assuming that phi1,phi2
+/// are already in the correct range.
+inline double dphi(double phi1, double phi2) {
+  return phi_in_range(phi1-phi2);
+}
+
+
+/// return the absolute difference between the two phi values, 
+/// placed in the correct range, assuming that phi1,phi2 are already
+/// in the correct range.
+inline double abs_dphi(double phi1, double phi2) {
+  double delta = fabs(phi1-phi2);
+  return delta > M_PI ? twopi-delta : delta;
+}
+
+/// return the square of the argument
+inline double pow2(double x) {return x*x;}
+
+
+/** 
+ * \class Ctwovect
+ * \brief class for holding a two-vector
+ */
+class Ctwovect {
+public:
+  /// default ctor
+  Ctwovect() : x(0.0), y(0.0) {}
+
+  /// ctor with initialisation
+  /// \param _x   first coordinate
+  /// \param _y   second coordinate
+  Ctwovect(double _x, double _y) : x(_x), y(_y) {}
+
+  /// vector coordinates
+  double x, y;
+
+  /// norm (modulud square) of the vector
+  inline double mod2() const {return pow2(x)+pow2(y);}
+
+  /// modulus of the vector
+  inline double modulus() const {return sqrt(mod2());}
+};
+
+
+/// dot product of two 2-vectors
+/// \param a   first 2-vect
+/// \param b   second 2-vect
+/// \return a.b is returned
+inline double dot_product(const Ctwovect & a, const Ctwovect & b) {
+  return a.x*b.x + a.y*b.y;
+}
+
+
+/// cross product of two 2-vectors
+/// \param a   first 2-vect
+/// \param b   second 2-vect
+/// \return a x b is returned
+inline double cross_product(const Ctwovect & a, const Ctwovect & b) {
+  return a.x*b.y - a.y*b.x;
+}
+
+
+/** 
+ * \class Ceta_phi_range
+ * \brief class for holding a covering range in eta-phi
+ *
+ * This class deals with ranges in the eta-phi plane. It
+ * implements methods to test if two ranges overlap and
+ * to take the union of two overlapping intervals.
+ */
+class Ceta_phi_range{
+public:
+  /// default ctor
+  Ceta_phi_range();
+
+  /// ctor with initialisation
+  /// we initialise with a centre (in eta,phi) and a radius
+  /// \param c_eta   eta coordinate of the centre
+  /// \param c_phi   phi coordinate of the centre
+  /// \param R       radius
+  Ceta_phi_range(double c_eta, double c_phi, double R);
+
+  /// assignment of range
+  /// \param r   range to assign to current one
+  Ceta_phi_range& operator = (const Ceta_phi_range &r);
+
+  /// add a particle to the range
+  /// \param eta  eta coordinate of the particle
+  /// \param phi  phi coordinate of the particle
+  /// \return 0 on success, 1 on error
+  int add_particle(const double eta, const double phi);
+
+  /// eta range as a binary coding of covered cells
+  unsigned int eta_range;     
+
+  /// phi range as a binary coding of covered cells
+  unsigned int phi_range;     
+
+  /// maximal value for eta
+  static double eta_min;
+  static double eta_max;
+
+private:
+  /// return the cell index corrsponding to an eta value
+  inline unsigned int get_eta_cell(double eta){
+    return (unsigned int) (1 << ((int) (32*((eta-eta_min)/(eta_max-eta_min)))));
+  }
+
+  /// return the cell index corrsponding to a phi value
+  inline unsigned int get_phi_cell(double phi){
+    return (unsigned int) (1 << ((int) (32*phi/twopi+16)%32));
+  }
+};
+
+/// test overlap
+/// \param  r1  first range
+/// \param  r2  second range
+/// \return true if overlap, false otherwise.
+bool is_range_overlap(const Ceta_phi_range &r1, const Ceta_phi_range &r2);
+
+/// compute union
+/// Note: we assume that the two intervals overlap
+/// \param  r1  first range
+/// \param  r2  second range
+/// \return union of the two ranges
+const Ceta_phi_range range_union(const Ceta_phi_range &r1, const Ceta_phi_range &r2);
+
+}
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/hash.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/hash.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/hash.h	(revision 11)
@@ -0,0 +1,117 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: hash.h                                                              //
+// Description: header file for classes hash_element and hash_cones          //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:11 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __HASH_H__
+#define __HASH_H__
+
+#include "../interface/momentum.h"
+#include "reference.h"
+
+namespace siscone{
+
+/**
+ * \class hash_element
+ * information on store cones candidates.
+ *
+ * We store in this class the information used to count all 
+ * protocones in a first pass. This first pass only count
+ * cones with different references and test their stbility
+ * with the parent-child particles (border particles).
+ */
+class hash_element{
+ public:
+  Creference ref;      ///< reference
+  double eta;          ///< centre: eta coordinate
+  double phi;          ///< centre: phi coordinate
+  bool is_stable;      ///< true if stable w.r.t. "border particles"
+
+  hash_element *next;  ///< pointer to the next element
+};
+
+/**
+ * \class hash_cones
+ * list of cones candidates.
+ *
+ * We store in this class all the hash_elements and give
+ * functions to manipulate them.
+ */
+class hash_cones{
+ public:
+  /// constructor with initialisation
+  /// \param _Np  number of particles
+  /// \param _R2  cone radius (squared)
+  hash_cones(int _Np, double _R2);
+
+  /// destructor
+  ~hash_cones();
+
+  /**
+   * insert a new candidate into the hash.
+   * \param v       4-momentum of te cone to add
+   * \param parent  parent particle defining the cone
+   * \param child   child particle defining the cone
+   * \param p_io    whether the parent has to belong to the cone or not
+   * \param c_io    whether the child has to belong to the cone or not
+   * \return 0 on success, 1 on error
+   */
+  int insert(Cmomentum *v, Cmomentum *parent, Cmomentum *child, bool p_io, bool c_io);
+
+  /**
+   * insert a new candidate into the hash.
+   * \param v       4-momentum of te cone to add
+   * Note, in this case, we assume stability. We also assume
+   * that eta and phi are computed for v
+   * \return 0 on success, 1 on error
+   */
+  int insert(Cmomentum *v);
+
+  /// the cone data itself
+  hash_element **hash_array;
+
+  /// number of elements
+  int n_cones;
+
+  /// number of cells-1
+  int mask;
+
+  /// circle radius (squared)
+  /// NOTE: need to be set before any call to 'insert'
+  double R2;
+
+  /**
+   * test if a particle is inside a cone of given centre.
+   * check if the particle of coordinates 'v' is inside the circle of radius R 
+   * centered at 'centre'.
+   * \param centre   centre of the circle
+   * \param v        particle to test
+   * \return true if inside, false if outside
+   */
+  inline bool is_inside(Cmomentum *centre, Cmomentum *v);
+};
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/momentum.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/momentum.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/momentum.h	(revision 11)
@@ -0,0 +1,157 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: momentum.h                                                          //
+// Description: header file for 4-momentum class Cmomentum                   //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:11 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __VECTOR_H__
+#define __VECTOR_H__
+
+#include <vector>
+#include <math.h>
+#include "../interface/reference.h"
+#include "../interface/geom_2d.h"
+#include "../interface/defines.h"
+
+namespace siscone{
+
+/**
+ * \class Cmomentum
+ * \brief base class for dynamic coordinates management
+ *
+ * This class contains the information for particle or group of
+ * particles management.
+ * It includes all Lorentz properties as well as tools for summing them.
+ * Note: 'sums' over phi angles are indeed averages. This allows to
+ *       deal with periodicity at each step
+ */
+class Cmomentum{
+ public:
+  /// default ctor
+  Cmomentum();
+
+  /// ctor with initialisation
+  Cmomentum(double _px, double _py, double _pz, double _E);
+
+  /// ctor with detailed initialisation
+  Cmomentum(double _eta, double _phi, Creference _ref);
+
+  /// default dtor
+  ~Cmomentum();
+
+  /// computes pT
+  inline double perp() const {return sqrt(perp2());}
+
+  /// computes pT^2
+  inline double perp2() const {return px*px+py*py;}
+
+  /// computes m
+  inline double mass() const {return sqrt(mass2());}
+
+  /// computes m^2
+  inline double mass2() const {return perpmass2()-perp2();}
+
+  /// transverse mass, mt = sqrt(pt^2+m^2) = sqrt(E^2 - pz^2)
+  inline double perpmass() const {return sqrt((E-pz)*(E+pz));}
+
+  /// transverse mass squared, mt^2 = pt^2+m^2 = E^2 - pz^2
+  inline double perpmass2() const {return (E-pz)*(E+pz);}
+
+  /// computes transverse energy
+  inline double Et() const {return E/sqrt(1.0+pz*pz/perp2());}
+
+  /// computes transverse energy (squared)
+  inline double Et2() const {return E*E/(1.0+pz*pz/perp2());}
+
+  /// assignment of vectors
+  Cmomentum& operator = (const Cmomentum &v);
+
+  /// addition of vectors
+  /// !!! WARNING !!! no updating of eta and phi !!!
+  const Cmomentum operator + (const Cmomentum &v);
+
+  /// incrementation of vectors
+  /// !!! WARNING !!! no updating of eta and phi !!!
+  Cmomentum& operator += (const Cmomentum &v);
+
+  /// decrementation of vectors
+  /// !!! WARNING !!! no updating of eta and phi !!!
+  Cmomentum& operator -= (const Cmomentum &v);
+
+  /// build eta-phi from 4-momentum info
+  /// !!!                WARNING                   !!!
+  /// !!! computing eta and phi is time-consuming  !!!
+  /// !!! use this whenever you need eta or phi    !!!
+  /// !!! automatically called for single-particle !!!
+  void build_etaphi();
+
+  double px;        ///< x-momentum
+  double py;        ///< y-momentum
+  double pz;        ///< z-momentum
+  double E;         ///< energy
+
+  double eta;       ///< particle pseudo-rapidity 
+  double phi;       ///< particle azimuthal angle
+  int parent_index; ///< particle number in the parent list
+  int index;        ///< internal particle number
+
+  //////////////////////////////////////////////
+  // the following part is used for checksums //
+  //////////////////////////////////////////////
+  Creference ref;   ///< reference number for the vector
+};
+
+/// ordering of two vectors
+/// this is by default done w.r.t. their references
+bool operator < (const Cmomentum &v1, const Cmomentum &v2);
+
+/// ordering of vectors in eta (e.g. used in collinear tests)
+bool momentum_eta_less(const Cmomentum &v1, const Cmomentum &v2);
+
+/// ordering of vectors in pt
+bool momentum_pt_less(const Cmomentum &v1, const Cmomentum &v2);
+
+
+//////////////////////////
+// some handy utilities //
+//////////////////////////
+
+/// get distance between to eta-phi points
+/// \param eta  eta coordinate of first point
+/// \param phi  phi coordinate of first point
+/// \param v    vector defining the second point
+inline double get_distance(double eta, double phi, Cmomentum *v){
+  double dx, dy;
+
+  dx = eta - v->eta;
+  dy = fabs(phi - v->phi);
+  if (dy>M_PI) 
+    dy -= twopi;
+
+  return dx*dx+dy*dy;
+}
+
+}
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/protocones.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/protocones.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/protocones.h	(revision 11)
@@ -0,0 +1,268 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: protocones.h                                                        //
+// Description: header file for stable cones determination (Cstable_cones)   //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __PROTOCONES_H__
+#define __PROTOCONES_H__
+
+#include "../interface/momentum.h"
+#include "vicinity.h"
+#include <stdio.h>
+#include <vector>
+#include <list>
+#include "../interface/hash.h"
+
+
+
+namespace siscone{
+
+/**
+ * \class Cborder_store
+ * 
+ * class for storing a border momentum (in context of co-circularity
+ * checks).
+
+ * This class essentially calculates angle of border point w.r.t.
+ * circle center (eta & phi), and provides a store of information
+ * about whether we are currently including this point in the
+ * candidate 
+ */
+class Cborder_store{
+public:
+  /// default ctor
+  Cborder_store(Cmomentum * momentum, double centre_eta, double centre_phi) : 
+    mom(momentum),  is_in(false) {
+    angle = atan2(mom->phi - centre_phi, mom->eta - centre_eta);
+  }
+
+  Cmomentum * mom;  ///< particle momentum
+  double angle;     ///< angle w.r.t. circle centre
+  bool   is_in;     ///< inclusion status of the particle
+};
+
+
+/// allows easy sorting of Cborder_store objects (which need to be
+/// ordered in angle).
+inline bool operator<(const Cborder_store & a, const Cborder_store & b) {
+  return a.angle < b.angle;
+}
+
+
+/**
+ * \class Cstable_cones
+ * \brief Computes the list of stable comes from a particle list.
+ *
+ * This class does the first fundamental task of te cone algorithm:
+ * it is used to compute the list of stable cones given a list
+ * of particles.
+ */
+class Cstable_cones : public Cvicinity{
+ public:
+  /// default ctor
+  Cstable_cones();
+
+  /// ctor with initialisation (sse init for details)
+  Cstable_cones(std::vector<Cmomentum> &_particle_list);
+
+  /// default dtor
+  ~Cstable_cones();
+
+  /**
+   * initialisation
+   * \param _particle_list  list of particles
+   */
+  void init(std::vector<Cmomentum> &_particle_list);
+
+  /**
+   * compute stable cones.
+   * This function really does the job i.e. computes
+   * the list of stable cones (in a seedless way)
+   * \param _radius   radius of the cones
+   * \return The number of stable cones found is returned
+   */
+  int get_stable_cones(double _radius);
+
+  /// list of stable cones
+  std::vector<Cmomentum> protocones;
+
+  /// list of candidates
+  hash_cones *hc;
+
+  /// total number of tested cones
+  int nb_tot;
+
+ protected:
+  /// cone radius
+  double R;
+
+  /// cone radius SQUARED
+  double R2;
+
+ private:
+  /// cone with a given particle as parent
+  /// this reduction to a single vector assumes we trust the checksums
+  Cmomentum cone;
+
+  /// child particle, taken in the 'vicinity' list
+  Cmomentum *child;
+
+  /// centre of the tested cone 
+  Cvicinity_elm *centre;
+
+  /// index in the particle list;
+  unsigned int centre_idx;
+
+  /// first cone used in the vicinity list
+  unsigned int first_cone;
+
+  /**
+   * initialise the cone.
+   * We take the first particle in the angular ordering to compute this one
+   * \return 0 on success, 1 on error
+   */
+  int init_cone();
+
+  /**
+   * test cones.
+   * We check if the cone(s) build with the present parent and child 
+   * are stable
+   * \return 0 on success 1 on error
+   */
+  int test_cone();
+
+  /**
+   * update the cone
+   * go to the next child for that parent and update 'cone' appropriately
+   * \return 0 if update candidate found, 1 otherwise
+   */
+  int update_cone();
+
+  /*
+   * run through the vicinity of the current parent and for each child
+   * indicate which members are cocircular...
+   */
+  void prepare_cocircular_lists();
+
+  /**
+   * check if we are in a situation of cocircularity.
+   * if it is the case, update and test in the corresponding way
+   * \return 'false' if no cocircularity detected, 'true' otherwise
+   * Note that if cocircularity is detected, we need to 
+   * recall 'update' from 'update' !!!
+   */
+  bool cocircular_check();
+
+  /**
+   * Routine for testing cocircular configurations in p^3 time,
+   * rather than 2^p time;
+   */
+  void test_cone_cocircular(Cmomentum & borderless_cone, 
+			    std::list<Cmomentum *> & border_list);
+
+  /**
+   * carry out the computations needed for the stability check of the
+   * candidate, using the border_vect to indicate which particles
+   * should / should not be in the stable cone; if the cone is stable
+   * insert it into the hash.
+   */
+  void test_stability(Cmomentum & candidate, 
+                      const std::vector<Cborder_store> & border_vect);
+
+  /**
+   * compute the cone contents by going once around the full set of
+   * circles and tracking the entry/exit status each time -- this sets
+   * up the inclusion information, which can then be directly used to
+   * calculate the cone momentum.
+   */
+  void compute_cone_contents();
+
+  /**
+   * compute the cone momentum from particle list.
+   * in this version, we use the 'pincluded' information
+   * from the Cviinity class
+   */
+  void recompute_cone_contents();
+
+  /*
+   * if we have gone beyond the acceptable threshold of change, compute
+   * the cone momentum from particle list.  in this version, we use the
+   * 'pincluded' information from the Cvicinity class, but we don't
+   * change the member cone, only the locally supplied one
+   */
+  void recompute_cone_contents_if_needed(Cmomentum & this_cone, double & this_dpt);
+
+  /**
+   * compute stability of all enumerated candidates.
+   * For all candidate cones which are stable w.r.t. their border particles,
+   * pass the last test: stability with quadtree intersection
+   */
+  int proceed_with_stability();
+
+  /*
+   * circle intersection.
+   * computes the intersection with a circle of given centre and radius.
+   * The output takes the form of a checkxor of the intersection's particles
+   *  - cx    circle centre x coordinate
+   *  - cy    circle centre y coordinate
+   * return the checkxor for the intersection
+   ******************************************************************/
+  Creference circle_intersect(double cx, double cy);
+
+  /// present candidate cone
+  Cmomentum cone_candidate;
+
+  /// in case of co-circular points, vector for them
+  std::vector<Cmomentum*> child_list;
+
+  /// list of cocircular enclusures already studied
+  /// first element if cone contents, second is cone border
+  std::vector< std::pair<Creference,Creference> > multiple_centre_done;
+
+  // information for updating cone contents to avoid rounding errors
+  double dpt;          ///< sums of Delta P_t
+
+  /**
+   * test if a particle is inside a cone of given centre.
+   * check if the particle of coordinates 'v' is inside the circle of radius R 
+   * centered at 'centre'.
+   * \param centre   centre of the circle
+   * \param v        particle to test
+   * \return true if inside, false if outside
+   */
+  inline bool is_inside(Cmomentum *centre, Cmomentum *v);
+};
+
+/*
+ * compute the absolute value of the difference between 2 angles.
+ * We take care of the 2pi periodicity
+ * \param angle1   first angle
+ * \param angle2   second angle
+ * \return the absolute value of the difference between the angles
+ *****************************************************************/
+inline double abs_dangle(double &angle1, double &angle2);
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/quadtree.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/quadtree.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/quadtree.h	(revision 11)
@@ -0,0 +1,124 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: quadtree.h                                                          //
+// Description: header file for quadtree management (Cquadtree class)        //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __QUADTREE_H__
+#define __QUADTREE_H__
+
+#include "../interface/momentum.h"
+#include <stdio.h>
+
+namespace siscone{
+
+/**
+ * \class Cquadtree
+ * \brief Implementation of a 2D quadtree.
+ *
+ * This class implements the traditional two-dimensional quadtree.
+ * The elements at each node are of 'Cmomentum' type.
+ */
+class Cquadtree{
+ public:
+  /// default ctor
+  Cquadtree();
+
+  /// ctor with initialisation (see init for details)
+  Cquadtree(double _x, double _y, double _half_size_x, double _half_size_y);
+
+  /// default destructor
+  /// at destruction, everything is destroyed except 
+  /// physical values at the leaves
+  ~Cquadtree();
+
+  /**
+   * init the tree.
+   * By initializing the tree, we mean setting the cell parameters
+   * and preparing the object to act as a seed for a new tree.
+   * \param _x            x-position of the center
+   * \param _y            y-position of the center
+   * \param _half_size_x  x-size of the cell
+   * \param _half_size_y  y-size of the cell
+   * \return 0 on success, 1 on error. Note that if the cell or its 
+   *         parent is already filled, we return an error.
+   */
+  int init(double _x, double _y, double _half_size_x, double _half_size_y);
+
+  /**
+   * adding a particle to the tree.
+   * This method adds one vector to the quadtree structure which 
+   * is updated consequently.
+   * \param v_add   vector to add
+   * \return 0 on success 1 on error
+   */
+  int add(Cmomentum *v_add);
+
+  /**
+   * circle intersection.
+   * computes the intersection with a circle of given centre and radius.
+   * The output takes the form of a quadtree with all squares included 
+   * in the circle.
+   * \param cx    circle centre x coordinate
+   * \param cy    circle centre y coordinate
+   * \param cR2   circle radius SQUARED
+   * \return the checksum for that intersection
+   */
+  Creference circle_intersect(double cx, double cy, double cR2);
+
+  /**
+   * output a data file for drawing the grid.
+   * This can be used to output a data file containing all the
+   * grid subdivisions. The file contents is as follows:
+   * first and second columns give center of the cell, the third 
+   * gives the size.
+   * \param flux  opened stream to write to
+   * \return 0 on success, 1 on error
+   */
+  int save(FILE *flux);
+
+  /**
+   * output a data file for drawing the tree leaves.
+   * This can be used to output a data file containing all the
+   * tree leaves. The file contents is as follows:
+   * first and second columns give center of the cell, the third 
+   * gives the size.
+   * \param flux  opened stream to write to
+   * \return 0 on success, 1 on error
+   */
+  int save_leaves(FILE *flux);
+
+  double centre_x;           ///< x-position of the centre of the cell
+  double centre_y;           ///< y-position of the centre of the cell
+  double half_size_x;        ///< HALF size of the cell
+  double half_size_y;        ///< HALF size of the cell
+
+  Cmomentum *v;              ///< physical contents
+
+  Cquadtree* children[2][2]; ///< sub-cells ( 0,1->left-right; 0,1->bottom,top)
+  bool has_child;            ///< true if not a leaf
+};
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/ranlux.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/ranlux.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/ranlux.h	(revision 11)
@@ -0,0 +1,49 @@
+//! \file ranlux.h
+
+#ifndef __RANLUX_H__
+#define __RANLUX_H__
+
+/* This is a lagged fibonacci generator with skipping developed by Luescher.
+   The sequence is a series of 24-bit integers, x_n, 
+
+   x_n = d_n + b_n
+
+   where d_n = x_{n-10} - x_{n-24} - c_{n-1}, b_n = 0 if d_n >= 0 and
+   b_n = 2^24 if d_n < 0, c_n = 0 if d_n >= 0 and c_n = 1 if d_n < 0,
+   where after 24 samples a group of p integers are "skipped", to
+   reduce correlations. By default p = 199, but can be increased to
+   365.
+
+   The period of the generator is around 10^171. 
+
+   From: M. Luescher, "A portable high-quality random number generator
+   for lattice field theory calculations", Computer Physics
+   Communications, 79 (1994) 100-110.
+
+   Available on the net as hep-lat/9309020 at http://xxx.lanl.gov/
+
+   See also,
+
+   F. James, "RANLUX: A Fortran implementation of the high-quality
+   pseudo-random number generator of Luscher", Computer Physics
+   Communications, 79 (1994) 111-114
+
+   Kenneth G. Hamilton, F. James, "Acceleration of RANLUX", Computer
+   Physics Communications, 101 (1997) 241-248
+
+   Kenneth G. Hamilton, "Assembler RANLUX for PCs", Computer Physics
+   Communications, 101 (1997) 249-253  */
+
+namespace siscone{
+
+/// initialize 'ranlux' generator
+void ranlux_init();
+
+/// generate random value (24 bits)
+unsigned long int ranlux_get();
+
+/// save state of the generator
+void ranlux_print_state();
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/reference.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/reference.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/reference.h	(revision 11)
@@ -0,0 +1,111 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: reference.h                                                         //
+// Description: header file for checkxor management (Creference class)       //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __REFERENCE_H__
+#define __REFERENCE_H__
+
+namespace siscone{
+
+/**
+ * \class Creference
+ * \brief references used for checksums.
+ *
+ * This class implements some reference variable
+ * that can be used for checksums. Those checksums
+ * are useful to disentengle between contents of two
+ * cones without looking into their explicit particle
+ * contents.
+ */
+class Creference{
+ public:
+  /// default constructor
+  Creference();
+
+  /// create a random reference
+  void randomize();
+
+  /// test emptyness
+  bool is_empty();
+
+  /// test non-emptyness
+  bool not_empty();
+
+  /// assignment of reference
+  Creference& operator = (const Creference &r);
+
+  /// addition of reference
+  Creference operator + (const Creference &r);
+
+  /// incrementation of reference
+  Creference& operator += (const Creference &r);
+
+  /// decrementation of reference
+  Creference& operator -= (const Creference &r);
+
+  /// accessing the reference
+  inline unsigned int operator[] (int i) {return ref[i];}
+
+  unsigned int ref[3];   ///< actual data for the reference
+};
+
+/// addition of two references
+Creference operator + (Creference &r1, Creference &r2);
+
+/// equality test of two references
+bool operator == (const Creference &r1, const Creference &r2);
+
+/// difference test of two references
+bool operator != (const Creference &r1, const Creference &r2);
+
+/// ordering of two references
+bool operator < (const Creference &r1, const Creference &r2);
+
+
+//=============== inline material ================
+
+// equality test for two references
+//----------------------------------
+inline bool operator == (const Creference &r1, const Creference &r2){
+  return (r1.ref[0]==r2.ref[0]) && (r1.ref[1]==r2.ref[1]) && (r1.ref[2]==r2.ref[2]);
+}
+
+// difference test for two references
+//----------------------------------
+inline bool operator != (const Creference &r1, const Creference &r2){
+  return (r1.ref[0]!=r2.ref[0]) || (r1.ref[1]!=r2.ref[1]) || (r1.ref[2]!=r2.ref[2]);
+}
+
+// difference test for two references
+//----------------------------------
+inline bool operator < (const Creference &r1, const Creference &r2){
+  return (r1.ref[0]<r2.ref[0]) || ((r1.ref[0]==r2.ref[0]) && 
+				   ((r1.ref[1]<r2.ref[1]) || ((r1.ref[1]==r2.ref[1]) && (r1.ref[2]<r2.ref[2]))
+				    ));
+}
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/siscone.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/siscone.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/siscone.h	(revision 11)
@@ -0,0 +1,127 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: siscone.h                                                           //
+// Description: header file for the main SISCone class                       //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __SISCONE_H__
+#define __SISCONE_H__
+
+#include "../interface/protocones.h"
+#include "../interface/split_merge.h"
+
+namespace siscone{
+
+/**
+ * \class Csiscone
+ * final class: gather everything to compute the jet contents.
+ * 
+ * This is the class user should use.
+ * It computes the jet contents of a list of particles
+ * given a cone radius and a threshold for splitting/merging.
+ *
+ * After the call to 'perform', the vector jets is filled with
+ * the jets found. the 'contents' field of each jets contains
+ * the indices of the particles included in that jet. 
+ */
+class Csiscone : public Cstable_cones, public Csplit_merge{
+ public:
+  /// default ctor
+  Csiscone();
+
+  /// default dtor
+  ~Csiscone();
+
+  /**
+   * compute the jets from a given particle set.
+   * We are doing multiple passes such pass n_pass looks for jets among 
+   * all particles not put into jets during previous passes.
+   * By default the number of passes is infinite (0). 
+   * \param _particles   list of particles
+   * \param _radius      cone radius
+   * \param _f           shared energy threshold for splitting&merging
+   * \param _n_pass_max  maximum number of passes (0=full search)
+   * \param _ptmin       minimum pT of the protojets
+   * \param _split_merge_scale    the scale choice for the split-merge procedure
+   *        NOTE: SM_pt leads to IR unsafety for some events with momentum conservation. 
+   *              SM_Et is IR safe but not boost invariant and not implemented(!)
+   *              SM_mt is IR safe for hadronic events, but not for decays of two 
+   *                    back-to-back particles of identical mass
+   *              SM_pttilde  
+   *                    is always IR safe, and also boost invariant (default)
+   *
+   * \return the number of jets found.
+   */
+  int compute_jets(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+		   int _n_pass_max=0, double _ptmin=0.0,
+		   Esplit_merge_scale _split_merge_scale=SM_pttilde);
+
+  /**
+   * recompute the jets with a different overlap parameter.
+   * we use the same particles and R as in the preceeding call.
+   * \param _f           shared energy threshold for splitting&merging
+   * \param _ptmin       minimum pT of the protojets
+   * \param _split_merge_scale    the scale choice for the split-merge procedure
+   *                                           split--merge variable
+   *        NOTE: using pt leads to IR unsafety for some events with momentum
+   *              conservation. So we strongly advise not to change the default
+   *              value.
+   * \return the number of jets found, -1 if recomputation not allowed.
+   */
+  int recompute_jets(double _f, double _ptmin = 0.0,
+		     Esplit_merge_scale _split_merge_scale=SM_pttilde);
+
+  /// list of protocones found pass-by-pass
+  std::vector<std::vector<Cmomentum> > protocones_list;
+
+  // random number initialisation
+  static bool init_done;      ///< check random generator initialisation
+
+ private:
+  bool rerun_allowed;         ///< is recompute_jets allowed ?
+};
+
+  
+// finally, a bunch of functions to access to 
+// basic information (package name, version)
+//---------------------------------------------
+
+/** 
+ * return SISCone package name.
+ * This is nothing but "SISCone", it is a replacement to the
+ * PACKAGE_NAME string defined in config.h and which is not
+ * public by default.
+ * \return the SISCone name as a string
+ */
+std::string siscone_package_name();
+
+/** 
+ * return SISCone version number.
+ * \return a string of the form "X.Y.Z" with possible additional tag
+ *         (alpha, beta, devel) to mention stability status
+ */
+std::string siscone_version();
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/siscone_error.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/siscone_error.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/siscone_error.h	(revision 11)
@@ -0,0 +1,57 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: siscone_error.h                                                     //
+// Description: header file for SISCone error messages (Csiscone_error)      //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __SISCONE_ERROR_H__
+#define __SISCONE_ERROR_H__
+
+#include<iostream>
+#include<string>
+
+namespace siscone{
+
+/// class corresponding to errors that will be thrown by siscone
+class Csiscone_error {
+public:
+  // constructors
+  Csiscone_error() {;};
+  Csiscone_error(const std::string & message) {
+    m_message = message; 
+    if (m_print_errors) std::cerr << "siscone::Csiscone_error: "<<message << std::endl;
+  };
+
+  std::string message() const {return m_message;};
+
+  static void setm_print_errors(bool print_errors) {
+    m_print_errors = print_errors;};
+
+private:
+  std::string m_message;
+  static bool m_print_errors;
+};
+
+}
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/split_merge.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/split_merge.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/split_merge.h	(revision 11)
@@ -0,0 +1,375 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: split_merge.h                                                       //
+// Description: header file for splitting/merging (contains the CJet class)  //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __SPLIT_MERGE_H__
+#define __SPLIT_MERGE_H__
+
+#include "../interface/defines.h"
+#include "../interface/geom_2d.h"
+#include "../interface/momentum.h"
+#include <stdio.h>
+#include <vector>
+#include <set>
+#include <memory>
+#include <string>
+
+namespace siscone{
+
+/**
+ * \class Cjet
+ * real Jet information.
+ *
+ * This class contains information for one single jet. 
+ * That is, first, its momentum carrying information
+ * about its centre and pT, and second, its particle
+ * contents
+ */
+class Cjet{
+ public:
+  /// default ctor
+  Cjet();
+
+  /// default dtor
+  ~Cjet();
+
+  Cmomentum v;               ///< jet momentum
+  double pt_tilde;           ///< p-scheme pt
+  int n;                     ///< number of particles inside
+  std::vector<int> contents; ///< particle contents (list of indices)
+
+  /// ordering variable used for ordering and overlap in the
+  /// split--merge. This variable is automatically set either to
+  /// pt_tilde, or to mt or to pt, depending on the siscone
+  /// parameter. Note that the default behaviour is pt_tilde and that
+  /// other chices may lead to infrared unsafe situations.
+  /// Note: we use the square of the varible rather than the variable itself
+  double sm_var2;
+
+  /// covered range in eta-phi
+  Ceta_phi_range range;
+
+  /// pass at which the jet has been found
+  /// It starts at 0 (first pass), -1 means infinite rapidity
+  int pass;
+};
+
+/// ordering of jets in pt (e.g. used in final jets ordering)
+bool jets_pt_less(const Cjet &j1, const Cjet &j2);
+  
+
+/// the choices of scale variable that can be used in the split-merge
+/// step, both for ordering the protojets and for measuing their
+/// overlap; pt, Et and mt=sqrt(pt^2+m^2) are all defined in E-scheme
+/// (4-momentum) recombination; pttilde = \sum_{i\in jet} |p_{t,i}|
+///
+/// NB: if one changes the order here, one _MUST_ also change the order
+///     in the SISCone plugin
+enum Esplit_merge_scale {
+           SM_pt,     ///< transverse momentum (E-scheme), IR unsafe
+           SM_Et,     ///< transverse energy (E-scheme), not long. boost inv.
+                      ///< original run-II choice [may not be implemented]
+           SM_mt,     ///< transverse mass (E-scheme), IR safe except
+                      ///< in decays of two identical narrow heavy particles
+           SM_pttilde ///< pt-scheme pt = \sum_{i in jet} |p_{ti}|, should
+                      ///< be IR safe in all cases
+};
+
+/// return the name of the split-merge scale choice
+std::string split_merge_scale_name(Esplit_merge_scale sms);
+
+/**
+ * \class Csplit_merge_comparison
+ * a class that allows us to carry out comparisons of pt of jets, using
+ * information from exact particle contents where necessary.
+ *
+ */
+class Csplit_merge_ptcomparison{
+public:
+  Csplit_merge_ptcomparison() : 
+    particles(0), split_merge_scale(SM_pttilde){};
+
+  // return the name corresponding to the SM scale variable
+  std::string SM_scale_name() const {
+    return split_merge_scale_name(split_merge_scale);}
+
+  std::vector<Cmomentum> * particles;
+  std::vector<double> * pt;
+  bool operator()(const Cjet &jet1, const Cjet &jet2) const;
+
+  /**
+   * get the difference between 2 jets, calculated such that rounding
+   * errors will not affect the result even if the two jets have
+   * almost the same content (so that the difference is below the
+   * rounding errors)
+   *
+   * \param j1        first jet
+   * \param j2        second jet
+   * \param v         jet1-jet2
+   * \param pt_tilde  jet1-jet2 pt_tilde
+   */
+  void get_difference(const Cjet &j1, const Cjet &j2, Cmomentum *v, double *pt_tilde) const;
+
+  /// the following parameter controls the variable we're using for 
+  /// the split-merge process i.e. the variable we use for 
+  ///  1. ordering jet candidates;
+  ///  2. computing te overlap fraction of two candidates.
+  /// The default value uses pttile (p-scheme pt). Other alternatives are
+  /// pt, mt=sqrt(pt^2+m^2)=sqrt(E^2-pz^2) or Et. 
+  /// NOTE: Modifying the default choice can have nasty effects:
+  /// - using pt leads to some IR unsafety when we have two jets,
+  ///   e.g. back-to-back, with the same pt. In that case, their ordering
+  ///   in pt is random and can be affected by the addition of a
+  ///   soft particle.  Hence, we highly recommand to keep this to
+  ///   the default value i.e.  to use pt only for the purpose of
+  ///   investigating the IR issue
+  /// - using Et is safe but do not respect boost invariance
+  /// - using mt solves the IR unsafety issues with the pt variable
+  ///   for QCD jets but the IR unsafety remains for nack-to-back 
+  ///   jets of unstable narrow-width particles (e.g. Higgs).
+  /// Therefore, keeping the default value is strongly advised.
+  Esplit_merge_scale split_merge_scale;
+};
+
+
+// iterator types
+/// iterator definition for the jet candidates structure
+typedef std::multiset<siscone::Cjet,Csplit_merge_ptcomparison>::iterator cjet_iterator;
+
+/// iterator definition for the jet structure
+typedef std::vector<siscone::Cjet>::iterator jet_iterator;
+
+
+
+/**
+ * \class Csplit_merge
+ * Class used to split and merge jets.
+ */
+class Csplit_merge{
+ public:
+  /// default ctor
+  Csplit_merge();
+
+  /// default dtor
+  ~Csplit_merge();
+
+
+  //////////////////////////////
+  // initialisation functions //
+  //////////////////////////////
+
+  /**
+   * initialisation function
+   * \param _particles  list of particles
+   * \param protocones  list of protocones (initial jet candidates)
+   * \param R2          cone radius (squared)
+   * \param ptmin       minimal pT allowed for jets
+   * \return 0 on success, 1 on error
+   */
+  int init(std::vector<Cmomentum> &_particles, std::vector<Cmomentum> *protocones, double R2, double ptmin=0.0);
+
+  /**
+   * initialisation function for particle list
+   * \param _particles  list of particles
+   * \return 0 on success, 1 on error
+   */
+  int init_particles(std::vector<Cmomentum> &_particles);
+
+  /**
+   * build initial list of left particles
+   */
+  int init_pleft();
+
+
+  ////////////////////////
+  // cleaning functions //
+  ////////////////////////
+
+  /// partial clearance
+  int partial_clear();
+
+  /// full clearance
+  int full_clear();
+
+
+  /////////////////////////////////
+  // main parts of the algorithm //
+  /////////////////////////////////
+ 
+  /**
+   * build the list 'p_uncol_hard' from p_remain by clustering
+   * collinear particles and removing particles softer than
+   * stable_cone_soft_pt2_cutoff
+   * note that thins in only used for stable-cone detection 
+   * so the parent_index field is unnecessary
+   */
+  int merge_collinear_and_remove_soft();
+
+  /**
+   * add a list of protocones
+   * \param protocones  list of protocones (initial jet candidates)
+   * \param R2          cone radius (squared)
+   * \param ptmin       minimal pT allowed for jets
+   * \return 0 on success, 1 on error
+   */
+  int add_protocones(std::vector<Cmomentum> *protocones, double R2, double ptmin=0.0);
+
+  /**
+   * really do the splitting and merging
+   * At the end, the vector jets is filled with the jets found.
+   * the 'contents' field of each jets contains the indices
+   * of the particles included in that jet. 
+   * \param overlap_tshold  threshold for splitting/merging transition
+   * \param ptmin           minimal pT allowed for jets
+   * \return the number of jets is returned
+   */
+  int perform(double overlap_tshold, double ptmin=0.0);
+
+
+  //////////////////////////////
+  // save and debug functions //
+  //////////////////////////////
+
+  /// save final jets
+  /// \param flux   stream to save the jet contentss
+  int save_contents(FILE *flux);
+
+  /// show jets/candidates status
+  int show();
+
+  // particle information
+  int n;                               ///< number of particles
+  std::vector<Cmomentum> particles;    ///< list of particles
+  std::vector<double> pt;              ///< list of particles' pt
+  int n_left;                          ///< numer of particles that does not belong to any jet
+  std::vector<Cmomentum> p_remain;     ///< list of particles remaining to deal with
+  std::vector<Cmomentum> p_uncol_hard; ///< list of particles remaining with collinear clustering
+  int n_pass;                          ///< index of the run
+
+  /// minimal difference in squared distance between a particle and
+  /// two overlapping protojets when doing a split (useful when
+  /// testing approx. collinear safety)
+  double most_ambiguous_split; 
+
+  // jets information
+  std::vector<Cjet> jets;            ///< list of jets
+
+  // working entries
+  int *indices;                      ///< maximal size array for indices works
+  int idx_size;                      ///< number of elements in indices1
+
+  /// The following flag indicates that identical protocones
+  /// are to be merged automatically each time around the split-merge
+  /// loop and before anything else happens.
+  ///
+  /// This flag is only effective if ALLOW_MERGE_IDENTICAL_PROTOCONES
+  /// is set in 'defines.h'
+  /// Note that this lead to infrared-unsafety so it is disabled
+  /// by default
+  bool merge_identical_protocones;
+
+  /// member used for detailed comparisons of pt's
+  Csplit_merge_ptcomparison ptcomparison;
+
+  /// stop split--merge when the SM_var of the hardest protojet 
+  /// is below this cut-off. 
+  /// This is not collinear-safe so you should not use this
+  /// variable unless you really know what you are doing
+  /// Note that the cut-off is set on the variable squared.
+  double SM_var2_hardest_cut_off;
+
+  /// pt cutoff for the particles to put in p_uncol_hard 
+  /// this is meant to allow removing soft particles in the
+  /// stable-cone search.
+  double stable_cone_soft_pt2_cutoff;
+
+ private:
+  /**
+   * get the overlap between 2 jets
+   * \param j1   first jet
+   * \param j2   second jet
+   * \param v    returned overlap^2 (determined by the choice of SM variable)
+   * \return true if overlapping, false if disjoint
+   */
+  bool get_overlap(const Cjet &j1, const Cjet &j2, double *v);
+
+
+  /**
+   * split the two given jets.
+   * during this procedure, the jets j1 & j2 are replaced
+   * by 2 new jets. Common particles are associted to the 
+   * closest initial jet.
+   * \param it_j1  iterator of the first jet in 'candidates'
+   * \param it_j2  iterator of the second jet in 'candidates'
+   * \param j1     first jet (Cjet instance)
+   * \param j2     second jet (Cjet instance)
+   * \return true on success, false on error
+   */
+  bool split(cjet_iterator &it_j1, cjet_iterator &it_j2);
+
+  /**
+   * merge the two given jet.
+   * during this procedure, the jets j1 & j2 are replaced
+   * by 1 single jets containing both of them.
+   * \param it_j1  iterator of the first jet in 'candidates'
+   * \param it_j2  iterator of the second jet in 'candidates'
+   * \return true on success, false on error
+   */
+  bool merge(cjet_iterator &it_j1, cjet_iterator &it_j2);
+
+  /**
+   * Check whether or not a jet has to be inserted in the 
+   * list of protojets. If it has, set its sm_variable and
+   * insert it to the list of protojets.
+   * \param jet    jet to insert
+   */
+  bool insert(Cjet &jet);
+
+  /**
+   * given a 4-momentum and its associated pT, return the 
+   * variable tht has to be used for SM
+   * \param v          4 momentum of the protojet
+   * \param pt_tilde   pt_tilde of the protojet
+   */
+  double get_sm_var2(Cmomentum &v, double &pt_tilde);
+
+  // jet information
+  /// list of jet candidates
+  std::auto_ptr<std::multiset<Cjet,Csplit_merge_ptcomparison> > candidates;
+
+  /// minimal pt2
+  double pt_min2;
+
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+  /// checkxor for the candidates (to avoid having twice the same contents)
+  std::set<Creference> cand_refs;
+#endif
+};
+
+}
+
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/interface/vicinity.h
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/interface/vicinity.h	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/interface/vicinity.h	(revision 11)
@@ -0,0 +1,156 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: vicinity.h                                                          //
+// Description: header file for particle vicinity (Cvicinity class)          //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __VICINITY_H__
+#define __VICINITY_H__
+
+#include <vector>
+#include <list>
+#include "../interface/momentum.h"
+#include "../interface/defines.h"
+#include "../interface/quadtree.h"
+
+namespace siscone{
+
+  
+
+/**
+ * \class Cvicinity_inclusion
+ * \brief a class to keep track of inclusion status in cone and in cocircular region
+ *        while using minimal resources
+ */
+class Cvicinity_inclusion {
+public:
+  /// default ctor
+  Cvicinity_inclusion() : cone(false), cocirc(false) {}
+
+  bool cone;    ///< flag for particle inclusion in the cone
+  bool cocirc;  ///< flag for particle inclusion in the border
+};
+
+
+/**
+ * \class Cvicinity_elm
+ * \brief element in the vicinity of a parent.
+ *
+ * class used to manage one points in the vicinity 
+ * of a parent point.
+ */
+class Cvicinity_elm{
+ public:
+  /// pointer to the second borderline particle
+  Cmomentum *v;
+
+  /// variable to tell if the particle is inside or outside the cone 
+  Cvicinity_inclusion *is_inside;   
+
+  // centre variables
+  double eta;              ///< eta coordinate of the center
+  double phi;              ///< phi coordinate of the center
+  double angle;            ///< angle with parent
+  bool side;               ///< true if angle on the positive side, false otherwise
+  double cocircular_range; ///< amount by which the angle can be varied while
+                           ///< maintaining this point within co-circularity margin
+
+  /// list of elements co-circular with this one
+  /// NB: empty list uses less mem than vector
+  std::list<Cvicinity_elm * > cocircular;                                          
+};
+
+/// ordering pointers to Cvicinity_elm
+bool ve_less(Cvicinity_elm *ve1, Cvicinity_elm *ve2);
+
+
+/**
+ * \class Cvicinity
+ * \brief list of element in the vicinity of a parent.
+ *
+ * class used to manage the points which are in the vicinity 
+ * of a parent point.
+ */
+class Cvicinity{
+ public:
+  /// default constructor
+  Cvicinity();
+
+  /// constructor with initialisation (see set_particle_list)
+  Cvicinity(std::vector<Cmomentum> &_particle_list);
+
+  /// default destructor
+  ~Cvicinity();
+
+  /**
+   * set the particle_list
+   * \param _particle_list   list of particles (type Cmomentum)
+   */ 
+  void set_particle_list(std::vector<Cmomentum> &_particle_list);
+
+  /**
+   * build the vicinity list from the list of points.
+   * \param _parent    reference particle
+   * \param _VR        vicinity radius
+   */
+  void build(Cmomentum *_parent, double _VR);
+
+  // cone kinematical information
+  Cmomentum *parent;         ///< parent vector
+  double VR;                 ///< radius of the vicinity
+  double VR2;                ///< squared radius of the vicinity
+  double R;                  ///< normal radius
+  double R2;                 ///< squared normal radius
+  double inv_R_EPS_COCIRC;   ///< R / EPSILON_COCIRCULAR
+  double inv_R_2EPS_COCIRC;  ///< R / (2*EPSILON_COCIRCULAR)
+
+  // particle list information
+  int n_part;                                 ///< number of particles
+  std::vector<Cmomentum> plist;               ///< the list of particles
+  std::vector<Cvicinity_inclusion> pincluded; ///< the inclusion state of particles
+  Cvicinity_elm *ve_list;                     ///< list of vicinity elements built from particle list (size=2*n)
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  Cquadtree *quadtree;                        ///< quadtree used for final stability tests
+#endif
+
+  // vicinity information
+  std::vector<Cvicinity_elm*> vicinity;       ///< list of points in parent's vicinity
+  unsigned int vicinity_size;                 ///< number of elements in vicinity
+
+ protected:
+  /**
+   * append a particle to the 'vicinity' list after
+   * having tested it and computed the angular-ordering quantities
+   * \param v   vector to test
+   */
+  void append_to_vicinity(Cmomentum *v);
+
+  // internal variables
+  double pcx;    ///< parent centre (eta)
+  double pcy;    ///< parent centre (phi)
+};
+
+}
+
+#endif
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/area.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/area.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/area.cc	(revision 11)
@@ -0,0 +1,339 @@
+// -*- C++ -*-
+///////////////////////////////////////////////////////////////////////////////
+// File: area.h                                                              //
+// Description: header file for the computation of jet area                  //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/area.h"
+#include "../interface/momentum.h"
+#include <stdlib.h>
+#include <iostream>
+
+namespace siscone{
+using namespace std;
+
+/*******************************************************
+ * Cjet_area implementation                            *
+ * real Jet information, including its area(s)         *
+ *                                                     *
+ * This class contains information for one single jet. *
+ * That is, first, its momentum carrying information   *
+ * about its centre and pT, and second, its particle   *
+ * contents (from CJeT).                               *
+ * Compared to the Cjet class, it also includes the    *
+ * passive and active areas of the jet computed using  *
+ * the Carea class.                                    *
+ *******************************************************/
+
+// default ctor
+//--------------
+Cjet_area::Cjet_area(){
+  active_area = passive_area = 0.0;
+}
+
+// jet-initiated ctor
+//-------------------
+Cjet_area::Cjet_area(Cjet &j){
+  v = j.v;
+  n = j.n;
+  contents = j.contents;
+
+  pass = j.pass;
+
+  pt_tilde = j.pt_tilde;
+  sm_var2 = j.sm_var2;
+
+  active_area = passive_area = 0.0;
+}
+
+// default dtor
+//--------------
+Cjet_area::~Cjet_area(){
+
+}
+
+
+/******************************************************************
+ * Csiscone_area implementation                                   *
+ * class for the computation of jet areas.                        *
+ *                                                                *
+ * This is the class user should use whenever you want to compute *
+ * the jet area (passive and active).                             *
+ * It uses the SISCone algorithm to perform the jet analysis.     *
+ ******************************************************************/
+
+// default ctor
+//-------------
+Carea::Carea(){
+  grid_size = 60;     // 3600 particles added
+  grid_eta_max = 6.0; // maybe having twice more points in eta than in phi should be nice
+  grid_shift = 0.5;   // 50% "shacking"
+
+  pt_soft = 1e-100;
+  pt_shift = 0.05;
+  pt_soft_min = 1e-90;
+}
+
+// default dtor
+//-------------
+Carea::~Carea(){
+  
+}
+  
+/*
+ * compute the jet areas from a given particle set.
+ * The parameters of this method are the ones which control the jet clustering alghorithm.
+ * Note that the pt_min is not allowed here soince the jet-area determination involves soft 
+ * particles/jets and thus is used internally.
+ *  - _particles   list of particles
+ *  - _radius      cone radius
+ *  - _f           shared energy threshold for splitting&merging
+ *  - _n_pass_max  maximum number of passes (0=full search, the default)
+ *  - _split_merge_scale    the scale choice for the split-merge procedure
+ *        NOTE: SM_pt leads to IR unsafety for some events with momentum conservation. 
+ *              SM_Et is IR safe but not boost invariant and not implemented(!)
+ *              SM_mt is IR safe for hadronic events, but not for decays of two 
+ *                    back-to-back particles of identical mass
+ *              SM_pttilde  
+ *                    is always IR safe, and also boost invariant (default)
+ *  - _hard_only   when this is set on, only hard jets are computed
+ *                 and not the purely ghosted jets (default: false)
+ * return the jets together with their areas
+ ********************************************************************************************/
+int Carea::compute_areas(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+			 int _n_pass_max, Esplit_merge_scale _split_merge_scale,
+			 bool _hard_only){
+
+  vector<Cmomentum> all_particles;
+
+  // put "hardest cut-off" if needed
+  // this avoids computation of ghosted jets when not required and 
+  // significantly shortens the SM.
+  if (_hard_only){
+    SM_var2_hardest_cut_off = pt_soft_min*pt_soft_min;
+  }
+
+  // clear potential previous runs
+  jet_areas.clear();
+
+  // put initial set of particles in the list
+  int n_hard = _particles.size();
+  all_particles = _particles;
+
+  // build the set of ghost particles and add them to the particle list
+  int i,j;
+  double eta,phi,pt;
+
+  for (i=0;i<grid_size;i++){
+    for (j=0;j<grid_size;j++){
+      eta = grid_eta_max*(-1.0+2.0*(i+0.5+grid_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))))/grid_size);
+      phi = M_PI        *(-1.0+2.0*(j+0.5+grid_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))))/grid_size);
+      pt  = pt_soft*(1.0+pt_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))));
+      all_particles.push_back(Cmomentum(pt*cos(phi),pt*sin(phi),pt*sinh(eta),pt*cosh(eta)));
+    }
+  }
+  
+  // run clustering with all particles.
+  // the split-merge here dynamically accounts for the purely soft jets.
+  // we therefore end up with the active area for the jets
+  compute_jets(all_particles, _radius, _f, _n_pass_max, 0.0, _split_merge_scale);
+
+  // save jets in the Cjet_area structure
+  // and determine their size
+  // jet contents is ordered by increasing index of the initial
+  // particles. Hence, we look for the first particle with index >= n_hard
+  // and deduce the number of ghosts in the jet, hence the area.
+  double area_factor = (2.0*grid_eta_max/grid_size)*(twopi/grid_size);
+  
+  for (i=0;i<(int) jets.size();i++){
+    jet_areas.push_back(jets[i]);
+    j=0;
+    while ((j<jets[i].n) && (jets[i].contents[j]<n_hard)) j++;
+    jet_areas[i].active_area = (jets[i].n-j)*area_factor;
+  }
+
+  // determine passive jet area
+  // for that onem we use the pt_min cut in order to remove purely
+  // soft jets from the SM procedure
+  recompute_jets(_f, pt_soft_min);
+
+  // for the area computation, we assume the jete order is the same!
+  for (i=0;i<(int) jets.size();i++){
+    j=0;
+    while ((j<jets[i].n) && (jets[i].contents[j]<n_hard)) j++;
+    jet_areas[i].passive_area = (jets[i].n-j)*area_factor;
+  }
+
+  // Note:
+  // there surely remain purely soft je at the end
+  // their active area is 0 by default (see ctor)
+
+  jets.clear();
+
+  return 0;
+}
+
+/*
+ * compute the passive jet areas from a given particle set.
+ * The parameters of this method are the ones which control the jet clustering alghorithm.
+ * Note that the pt_min is not allowed here soince the jet-area determination involves soft 
+ * particles/jets and thus is used internally.
+ *  - _particles   list of particles
+ *  - _radius      cone radius
+ *  - _f           shared energy threshold for splitting&merging
+ *  - _n_pass_max  maximum number of passes (0=full search, the default)
+ *  - _split_merge_scale    the scale choice for the split-merge procedure
+ *        NOTE: SM_pt leads to IR unsafety for some events with momentum conservation. 
+ *              SM_Et is IR safe but not boost invariant and not implemented(!)
+ *              SM_mt is IR safe for hadronic events, but not for decays of two 
+ *                    back-to-back particles of identical mass
+ *              SM_pttilde  
+ *                    is always IR safe, and also boost invariant (default)
+ * return the jets together with their passive areas
+ ********************************************************************************************/
+int Carea::compute_passive_areas(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+				 int _n_pass_max, Esplit_merge_scale _split_merge_scale){
+
+  vector<Cmomentum> all_particles;
+
+  // clear potential previous runs
+  jet_areas.clear();
+
+  // put initial set of particles in the list
+  int n_hard = _particles.size();
+  all_particles = _particles;
+
+  // build the set of ghost particles and add them to the particle list
+  int i,j;
+  double eta,phi,pt;
+
+  for (i=0;i<grid_size;i++){
+    for (j=0;j<grid_size;j++){
+      eta = grid_eta_max*(-1.0+2.0*(i+0.5+grid_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))))/grid_size);
+      phi = M_PI        *(-1.0+2.0*(j+0.5+grid_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))))/grid_size);
+      pt  = pt_soft*(1.0+pt_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))));
+      all_particles.push_back(Cmomentum(pt*cos(phi),pt*sin(phi),pt*sinh(eta),pt*cosh(eta)));
+    }
+  }
+  
+  // determine passive jet area
+  // for that onem we use the pt_min cut in order to remove purely
+  // soft jets from the SM procedure
+  compute_jets(all_particles, _radius, _f, _n_pass_max, pt_soft_min, _split_merge_scale);
+
+  // save jets in the Cjet_area structure
+  // and determine their size
+  // jet contents is ordered by increasing index of the initial
+  // particles. Hence, we look for the first particle with index >= n_hard
+  // and deduce the number of ghosts in the jet, hence the area.
+  double area_factor = (2.0*grid_eta_max/grid_size)*(twopi/grid_size);
+  for (i=0;i<(int) jets.size();i++){
+    j=0;
+    while ((j<jets[i].n) && (jets[i].contents[j]<n_hard)) j++;
+    jet_areas[i].passive_area = (jets[i].n-j)*area_factor;
+  }
+
+  jets.clear();
+
+  return 0;
+}
+
+/*
+ * compute the active jet areas from a given particle set.
+ * The parameters of this method are the ones which control the jet clustering alghorithm.
+ * Note that the pt_min is not allowed here soince the jet-area determination involves soft 
+ * particles/jets and thus is used internally.
+ *  - _particles   list of particles
+ *  - _radius      cone radius
+ *  - _f           shared energy threshold for splitting&merging
+ *  - _n_pass_max  maximum number of passes (0=full search, the default)
+ *  - _split_merge_scale    the scale choice for the split-merge procedure
+ *        NOTE: SM_pt leads to IR unsafety for some events with momentum conservation. 
+ *              SM_Et is IR safe but not boost invariant and not implemented(!)
+ *              SM_mt is IR safe for hadronic events, but not for decays of two 
+ *                    back-to-back particles of identical mass
+ *              SM_pttilde  
+ *                    is always IR safe, and also boost invariant (default)
+ *  - _hard_only   when this is set on, only hard jets are computed
+ *                 and not the purely ghosted jets (default: false)
+ * return the jets together with their active areas
+ ********************************************************************************************/
+int Carea::compute_active_areas(std::vector<Cmomentum> &_particles, double _radius, double _f, 
+				int _n_pass_max, Esplit_merge_scale _split_merge_scale,
+				bool _hard_only){
+
+  vector<Cmomentum> all_particles;
+
+  // put "hardest cut-off" if needed
+  // this avoids computation of ghosted jets when not required and 
+  // significantly shortens the SM.
+  if (_hard_only){
+    SM_var2_hardest_cut_off = pt_soft_min*pt_soft_min;
+  }
+
+  // clear potential previous runs
+  jet_areas.clear();
+
+  // put initial set of particles in the list
+  int n_hard = _particles.size();
+  all_particles = _particles;
+
+  // build the set of ghost particles and add them to the particle list
+  int i,j;
+  double eta,phi,pt;
+
+  for (i=0;i<grid_size;i++){
+    for (j=0;j<grid_size;j++){
+      eta = grid_eta_max*(-1.0+2.0*(i+0.5+grid_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))))/grid_size);
+      phi = M_PI        *(-1.0+2.0*(j+0.5+grid_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))))/grid_size);
+      pt  = pt_soft*(1.0+pt_shift*(-1.0+2.0*(rand()/(RAND_MAX+1.0))));
+      all_particles.push_back(Cmomentum(pt*cos(phi),pt*sin(phi),pt*sinh(eta),pt*cosh(eta)));
+    }
+  }
+  
+  // run clustering with all particles.
+  // the split-merge here dynamically accounts for the purely soft jets.
+  // we therefore end up with the active area for the jets
+  compute_jets(all_particles, _radius, _f, _n_pass_max, 0.0, _split_merge_scale);
+
+  // save jets in the Cjet_area structure
+  // and determine their size
+  // jet contents is ordered by increasing index of the initial
+  // particles. Hence, we look for the first particle with index >= n_hard
+  // and deduce the number of ghosts in the jet, hence the area.
+  double area_factor = (2.0*grid_eta_max/grid_size)*(twopi/grid_size);
+  
+  for (i=0;i<(int) jets.size();i++){
+    jet_areas.push_back(jets[i]);
+    j=0;
+    while ((j<jets[i].n) && (jets[i].contents[j]<n_hard)) j++;
+    jet_areas[i].active_area = (jets[i].n-j)*area_factor;
+  }
+
+  jets.clear();
+
+  return 0;
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/geom_2d.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/geom_2d.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/geom_2d.cc	(revision 11)
@@ -0,0 +1,150 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: geom_2d.cpp                                                         //
+// Description: source file for two-dimensional geometry tools               //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/geom_2d.h"
+#include <algorithm>
+
+namespace siscone{
+
+#define PHI_RANGE_MASK 0xFFFFFFFF
+
+/*********************************************************
+ * class Ceta_phi_range implementation                   *
+ * class for holding a covering range in eta-phi         *
+ *                                                       *
+ * This class deals with ranges in the eta-phi plane. It *
+ * implements methods to test if two ranges overlap and  *
+ * to take the union of two overlapping intervals.       *
+ *********************************************************/
+
+using namespace std;
+
+// static member default init
+//----------------------------
+double Ceta_phi_range::eta_min = -100.0;
+double Ceta_phi_range::eta_max = 100.0;
+
+// default ctor
+//--------------
+Ceta_phi_range::Ceta_phi_range(){
+  eta_range = 0;
+  phi_range = 0;
+}
+
+// ctor with initialisation
+// we initialise with a centre (in eta,phi) and a radius
+//  - c_eta   eta coordinate of the centre
+//  - c_phi   phi coordinate of the centre
+//  - R       radius
+//-------------------------------------------------------
+Ceta_phi_range::Ceta_phi_range(double c_eta, double c_phi, double R){
+  // determination of the eta range
+  //-------------------------------
+  double xmin = max(c_eta-R,eta_min+0.0001);
+  double xmax = min(c_eta+R,eta_max-0.0001);
+
+  unsigned int cell_min = get_eta_cell(xmin);
+  unsigned int cell_max = get_eta_cell(xmax);
+
+  // warning: if cell_max==2^31, 2*cell_max==0 hence, 
+  // even if the next formula is formally (2*cell_max-cell_min),
+  // expressing it as (cell_max-cell_min)+cell_max is safe.
+  eta_range = (cell_max-cell_min)+cell_max;
+
+  // determination of the phi range
+  // !! taking care of periodicity !!
+  //---------------------------------
+  xmin = phi_in_range(c_phi-R);
+  xmax = phi_in_range(c_phi+R);
+
+  cell_min = get_phi_cell(xmin);
+  cell_max = get_phi_cell(xmax);
+
+  // Also, if the interval goes through pi, inversion is needed
+  if (xmax>xmin)
+    phi_range = (cell_max-cell_min)+cell_max;
+  else {
+    phi_range = (cell_min==cell_max) 
+      ? PHI_RANGE_MASK
+      : ((PHI_RANGE_MASK^(cell_min-cell_max)) + cell_max);
+  }
+}
+
+// assignment of range
+//  - r   range to assign to current one
+//---------------------------------------
+Ceta_phi_range& Ceta_phi_range::operator = (const Ceta_phi_range &r){
+  eta_range = r.eta_range;
+  phi_range = r.phi_range;
+
+  return *this;
+}
+
+// add a particle to the range
+//  - eta  eta coordinate of the particle
+//  - phi  phi coordinate of the particle
+// \return 0 on success, 1 on error
+//----------------------------------------
+int Ceta_phi_range::add_particle(const double eta, const double phi){
+  // deal with the eta coordinate
+  eta_range |= get_eta_cell(eta);
+
+  // deal with the phi coordinate
+  phi_range |= get_phi_cell(phi);
+
+  return 0;
+}
+
+
+// test overlap
+//  - r1  first range
+//  - r2  second range
+// return true if overlap, false otherwise.
+//------------------------------------------
+bool is_range_overlap(const Ceta_phi_range &r1, const Ceta_phi_range &r2){
+  // check overlap in eta AND phi
+  return ((r1.eta_range & r2.eta_range) && (r1.phi_range & r2.phi_range));
+}
+
+// compute union
+// Note: we assume that the two intervals overlap
+//  - r1  first range
+//  - r2  second range
+// \return union of the two ranges
+//------------------------------------------
+const Ceta_phi_range range_union (const Ceta_phi_range &r1, const Ceta_phi_range &r2){
+  Ceta_phi_range tmp;
+
+  // compute union in eta
+  tmp.eta_range = r1.eta_range | r2.eta_range;
+
+  // compute union in phi
+  tmp.phi_range = r1.phi_range | r2.phi_range;
+
+  return tmp;
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/hash.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/hash.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/hash.cc	(revision 11)
@@ -0,0 +1,217 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: hash.cpp                                                            //
+// Description: source file for classes hash_element and hash_cones          //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <math.h>
+#include <stdio.h>
+#include "../interface/hash.h"
+#include <iostream>
+
+namespace siscone{
+
+using namespace std;
+
+/**************************************************************
+ * implementation of hash_cones                               *
+ * list of cones candidates.                                  *
+ * We store in this class all the hash_elements and give      *
+ * functions to manipulate them.                              *
+ **************************************************************/
+
+// constructor with initialisation
+//  - _Np  number of particles
+//  - _R2  cone radius (squared)
+//-----------------------------------
+hash_cones::hash_cones(int _Np, double _R2){
+  int i;
+
+  n_cones = 0;
+
+  // determine hash size
+  mask = 1 << (int) (2*log(double(_Np))/log(2.0));
+  if (mask<=1) mask=2;
+
+  // create hash
+  hash_array = new hash_element*[mask];
+  mask--;
+
+  // set the array to 0
+  //? needed ?
+  for (i=0;i<mask+1;i++)
+    hash_array[i] = NULL;
+
+  R2 = _R2;
+}
+
+// destructor
+//------------
+hash_cones::~hash_cones(){
+  int i;
+  hash_element *elm;
+
+  for (i=0;i<mask+1;i++){
+    while (hash_array[i]!=NULL){
+      elm = hash_array[i];
+      hash_array[i] = hash_array[i]->next;
+      delete elm;
+    }
+  }
+
+  delete[] hash_array;
+}
+
+
+/*
+ * insert a new candidate into the hash.
+ *  - v       4-momentum of the cone to add
+ *  - parent  parent particle defining the cone
+ *  - child   child particle defining the cone
+ *  - p_io    whether the parent has to belong to the cone or not
+ *  - c_io    whether the child has to belong to the cone or not
+ * return 0 on success, 1 on error
+ ***********************************************************************/
+int hash_cones::insert(Cmomentum *v, Cmomentum *parent, Cmomentum *child, bool p_io, bool c_io){
+  hash_element *elm;
+  int index = (v->ref.ref[0]) & mask;
+
+  // check the array cell corresponding to our reference
+  elm = hash_array[index];
+  do{
+    // if it is not present, add it
+    if (elm==NULL){
+      // create element
+      elm = new hash_element;
+
+      // set its varibles
+      // Note: at this level, eta and phi have already been computed
+      //       through Cmomentum::build_etaphi.
+      elm->ref = v->ref;
+      
+      //compute vectors centre
+      v->build_etaphi();
+      elm->eta = v->eta;
+      elm->phi = v->phi;
+      // if at least one of the two is_inside tests gives a result != from the expected,
+      // the || will be true hence !(...) false as wanted
+      elm->is_stable = !((is_inside(v, parent)^p_io)||(is_inside(v, child)^c_io));
+      //cout << "-- new status of " <<  v->ref[0] << ":" << elm->is_stable << endl;
+
+      // update hash
+      elm->next = hash_array[index];
+      hash_array[index] = elm;
+      
+      n_cones++;
+      return 0;
+    }
+
+    // if the cone is already there, simply update stability status
+    if (v->ref == elm->ref){
+      // there is only an update to perform to see if the cone is still stable
+      if (elm->is_stable){
+	v->build_etaphi();
+	elm->is_stable = !((is_inside(v, parent)^p_io)||(is_inside(v, child)^c_io));
+        //cout << " parent/child: " 
+        //     << parent->ref[0] << ":" << is_inside(v, parent) << ":" << p_io << " "
+        //     << child->ref[0] << ":" << is_inside(v, child) << ":" << c_io << endl;
+        //cout << "-- rep status of " <<  v->ref[0] << ":" << elm->is_stable << endl;
+        //cout << v->eta << " " << v->phi << endl;
+        //cout << (child->eta) << " " << child->phi << endl;
+      }
+      return 0;
+    }
+
+    elm = elm->next;
+  } while (1);
+
+  return 1;
+}
+
+/*
+ * insert a new candidate into the hash.
+ *  - v       4-momentum of te cone to add
+ * Note, in this case, we assume stability. We also assume
+ * that eta and phi are computed for v
+ * return 0 on success, 1 on error
+ ***********************************************************************/
+int hash_cones::insert(Cmomentum *v){
+  hash_element *elm;
+  int index = (v->ref.ref[0]) & mask;
+  //cout << "-- stable candidate: " << v->ref[0] << ":" << endl;
+
+  // check the array cell corresponding to our reference
+  elm = hash_array[index];
+  do{
+    // if it is not present, add it
+    if (elm==NULL){
+      // create element
+      elm = new hash_element;
+
+      // set its varibles
+      // Note: at this level, eta and phi have already been computed
+      //       through Cmomentum::build_etaphi.
+      elm->ref = v->ref;
+      elm->eta = v->eta;
+      elm->phi = v->phi;
+      elm->is_stable = true;
+
+      // update hash
+      elm->next = hash_array[index];
+      hash_array[index] = elm;
+      
+      n_cones++;
+      return 0;
+    }
+
+    // if the cone is already there, we have nothing to do
+    if (v->ref == elm->ref){
+      return 0;
+    }
+
+    elm = elm->next;
+  } while (1);
+
+  return 1;
+}
+
+/*
+ * test if a particle is inside a cone of given centre.
+ * check if the particle of coordinates 'v' is inside the circle of radius R 
+ * centered at 'centre'.
+ *  - centre   centre of the circle
+ *  - v        particle to test
+ * return true if inside, false if outside
+ ******************************************************************************/
+inline bool hash_cones::is_inside(Cmomentum *centre, Cmomentum *v){
+  double dx, dy;
+
+  dx = centre->eta - v->eta;
+  dy = fabs(centre->phi - v->phi);
+  if (dy>M_PI) 
+    dy -= 2.0*M_PI;
+      
+  return dx*dx+dy*dy<R2;
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/momentum.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/momentum.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/momentum.cc	(revision 11)
@@ -0,0 +1,161 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: momentum.cpp                                                        //
+// Description: source file for 4-momentum class Cmomentum                   //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/momentum.h"
+#include <math.h>
+#include <stdlib.h>
+
+namespace siscone{
+
+/*************************************************************************
+ * class Cmomentum                                                       *
+ * This class contains the information for particle or group of          *
+ * particles management.                                                 *
+ * It includes all Lorentz properties as well as tools for summing them. *
+ *************************************************************************/
+ 
+// default ctor
+//--------------
+Cmomentum::Cmomentum(){
+  eta = 0.0;
+  phi = 0.0;
+  px = py = pz = E = 0.0;
+  ref = Creference();
+  index = -1;
+}
+
+// ctor with initialisation
+//--------------------------
+Cmomentum::Cmomentum(double _px, double _py, double _pz, double _E){
+  px = _px;
+  py = _py;
+  pz = _pz;
+  E  = _E;
+
+  // compute eta and phi
+  build_etaphi();
+  ref = Creference();
+}
+
+// ctor with detailed initialisation
+//-----------------------------------
+Cmomentum::Cmomentum(double _eta, double _phi, Creference _ref){
+  eta = _eta;
+  phi = _phi;
+
+  ref = _ref;
+}
+
+// default dtor
+//--------------
+Cmomentum::~Cmomentum(){
+
+}
+
+// assignment of vectors
+//-----------------------
+Cmomentum& Cmomentum::operator = (const Cmomentum &v){
+  px = v.px;
+  py = v.py;
+  pz = v.pz;
+  E  = v.E;
+
+  eta = v.eta;
+  phi = v.phi;
+
+  ref = v.ref;
+  return *this;
+}
+
+// addition of vectors
+// !!! WARNING !!! no updating of eta and phi !!!
+//------------------------------------------------
+const Cmomentum Cmomentum::operator + (const Cmomentum &v){
+  Cmomentum tmp = *this;
+  return tmp+=v;
+}
+
+// incrementation of vectors
+// !!! WARNING !!! no updating of eta and phi !!!
+//------------------------------------------------
+Cmomentum& Cmomentum::operator += (const Cmomentum &v){
+  px+=v.px;
+  py+=v.py;
+  pz+=v.pz;
+  E +=v.E;
+
+  ref+=v.ref;
+
+  return *this;
+}
+
+// incrementation of vectors
+// !!! WARNING !!! no updating of eta and phi !!!
+//------------------------------------------------
+Cmomentum& Cmomentum::operator -= (const Cmomentum &v){
+  px-=v.px;
+  py-=v.py;
+  pz-=v.pz;
+  E -=v.E;
+
+  ref-=v.ref;
+  return *this;
+}
+
+// build eta-phi from 4-momentum info
+// !!!                WARNING                   !!!
+// !!! computing eta and phi is time-consuming  !!!
+// !!! use this whenever you need eta or phi    !!!
+// !!! automatically called for single-particle !!!
+//--------------------------------------------------
+void Cmomentum::build_etaphi(){
+  // note: the factor n (ref.nb) cancels in all expressions !!
+  eta = 0.5*log((E+pz)/(E-pz));
+  phi = atan2(py,px);
+}
+
+
+// ordering of two vectors
+// the default ordering is w.r.t. their references
+//-------------------------------------------------
+bool operator < (const Cmomentum &v1, const Cmomentum &v2){
+  return v1.ref < v2.ref;
+}
+
+// ordering of vectors in eta (e.g. used in collinear tests)
+//-----------------------------------------------------------
+bool momentum_eta_less(const Cmomentum &v1, const Cmomentum &v2){
+  return v1.eta < v2.eta;
+}
+
+// ordering of vectors in pt
+//---------------------------
+bool momentum_pt_less(const Cmomentum &v1, const Cmomentum &v2){
+  return v1.perp2() < v2.perp2();
+}
+
+}
+
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/protocones.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/protocones.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/protocones.cc	(revision 11)
@@ -0,0 +1,838 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: protocones.cpp                                                      //
+// Description: source file for stable cones determination (Cstable_cones)   //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+/*******************************************************
+ * Introductory note:                                  *
+ * Since this file has many member functions, we have  *
+ * structured them in categories:		       *
+ * INITIALISATION FUNCTIONS                            *
+ *  - ctor()                                           *
+ *  - ctor(particle_list)                              *
+ *  - dtor()                                           *
+ *  - init(particle_list)                              *
+ * ALGORITHM MAIN ENTRY                                *
+ *  - get_stable_cone(radius)                          *
+ * ALGORITHM MAIN STEPS                                *
+ *  - init_cone()                                      *
+ *  - test_cone()                                      *
+ *  - update_cone()                                    *
+ *  - proceed_with_stability()                         *
+ * ALGORITHM MAIN STEPS FOR COCIRCULAR SITUATIONS      *
+ *  - cocircular_pt_less(v1, v2)                       *
+ *  - prepare_cocircular_list()                        *
+ *  - test_cone_cocircular()                           *
+ *  - test_stability(candidate, border_list)           *
+ *  - updat_cone_cocircular()                          *
+ * RECOMPUTATION OF CONE CONTENTS                      *
+ *  - compute_cone_contents()                          *
+ *  - recompute_cone_contents()                        *
+ *  - recompute_cone_contents_if_needed()              *
+ * VARIOUS TOOLS                                       *
+ *  - circle_intersect()                               *
+ *  - is_inside()                                      *
+ *  - abs_dangle()                                     *
+ *******************************************************/
+
+#include "../interface/protocones.h"
+#include "../interface/siscone_error.h"
+#include "../interface/defines.h"
+#include <math.h>
+#include <iostream>
+#include "../interface/circulator.h"
+#include <algorithm>
+
+namespace siscone{
+
+using namespace std;
+
+/**********************************************************************
+ * Cstable_cones implementation                                       *
+ * Computes the list of stable comes from a particle list.            *
+ * This class does the first fundamental task of te cone algorithm:   *
+ * it is used to compute the list of stable cones given a list        *
+ * of particles.                                                      *
+ **********************************************************************/
+
+////////////////////////////////////////////////////////
+// INITIALISATION FUNCTIONS                           //
+//  - ctor()                                          //
+//  - ctor(particle_list)                             //
+//  - dtor()                                          //
+//  - init(particle_list)                             //
+////////////////////////////////////////////////////////
+
+// default ctor
+//--------------
+Cstable_cones::Cstable_cones(){
+  nb_tot = 0;
+  hc = NULL;
+}
+
+// ctor with initialisation
+//--------------------------
+Cstable_cones::Cstable_cones(vector<Cmomentum> &_particle_list)
+  : Cvicinity(_particle_list){
+
+  nb_tot = 0;
+  hc = NULL;
+}
+
+// default dtor
+//--------------
+Cstable_cones::~Cstable_cones(){
+  if (hc!=NULL) delete hc;
+}
+
+/*
+ * initialisation
+ *  - _particle_list  list of particles
+ *  - _n              number of particles
+ *********************************************************************/
+void Cstable_cones::init(vector<Cmomentum> &_particle_list){
+  // check already allocated mem
+  if (hc!=NULL){
+    delete hc;
+  }
+  if (protocones.size()!=0)
+    protocones.clear();
+
+  multiple_centre_done.clear();
+
+  // initialisation
+  set_particle_list(_particle_list);
+}
+
+
+////////////////////////////////////////////////////////
+// ALGORITHM MAIN ENTRY                               //
+//  - get_stable_cone(radius)                         //
+////////////////////////////////////////////////////////
+
+/*
+ * compute stable cones.
+ * This function really does the job i.e. computes
+ * the list of stable cones (in a seedless way)
+ *  - _radius:  radius of the cones
+ * The number of stable cones found is returned
+ *********************************************************************/
+int Cstable_cones::get_stable_cones(double _radius){
+  int p_idx;
+
+  // check if everything is correctly initialised
+  if (n_part==0){
+    return 0;
+  }
+
+  R  = _radius;
+  R2 = R*R;
+
+  // allow hash for cones candidates
+  hc = new hash_cones(n_part, R2);
+
+  // browse all particles
+  for (p_idx=0;p_idx<n_part;p_idx++){
+    // step 0: compute the child list CL.
+    //         Note that this automatically sets the parent P
+    build(&plist[p_idx], 2.0*R);
+
+    // special case: 
+    //   if the vicinity is empty, the parent particle is a 
+    //   stable cone by itself. Add it to protocones list.
+    if (vicinity_size==0){
+      protocones.push_back(*parent);
+      continue;
+    }
+
+    // step 1: initialise with the first cone candidate
+    init_cone();
+
+    do{
+      // step 2: test cone stability for that pair (P,C)
+      test_cone();
+
+      // step 3: go to the next cone child candidate C
+    } while (!update_cone());
+  }
+
+  return proceed_with_stability();
+}
+
+
+////////////////////////////////////////////////////////
+// ALGORITHM MAIN STEPS                               //
+//  - init_cone()                                     //
+//  - test_cone()                                     //
+//  - update_cone()                                   //
+//  - proceed_with_stability()                        //
+////////////////////////////////////////////////////////
+
+/*
+ * initialise the cone.
+ * We take the first particle in the angular ordering to compute 
+ * this one
+ * return 0 on success, 1 on error
+ *********************************************************************/
+int Cstable_cones::init_cone(){
+  // The previous version of the algorithm was starting the 
+  // loop around vicinity elements with the "most isolated" child.
+  // given the nodist method to calculate the cone contents, we no
+  // longer need to worry about which cone comes first...
+  first_cone=0;
+
+  // now make sure we have lists of the cocircular particles
+  prepare_cocircular_lists();
+
+  //TODO? deal with a configuration with only degeneracies ? 
+  // The only possibility seems a regular hexagon with a parent point
+  // in the centre. And this situation is by itself unclear.
+  // Hence, we do nothing here !
+
+  // init set child C
+  centre = vicinity[first_cone];
+  child = centre->v;
+  centre_idx = first_cone;
+
+  // build the initial cone (nodist: avoids calculating distances --
+  // just deduces contents by circulating around all in/out operations)
+  // this function also sets the list of included particles
+  compute_cone_contents();
+  
+  return 0;
+}
+
+
+/*
+ * test cones.
+ * We check if the cone(s) built with the present parent and child 
+ * are stable
+ * return 0 on success 1 on error
+ *********************************************************************/
+int Cstable_cones::test_cone(){
+  Creference weighted_cone_ref;
+  
+  // depending on the side we are taking the child particle,
+  // we test different configuration.
+  // Each time, two configurations are tested in such a way that
+  // all 4 possible cases (parent or child in or out the cone)
+  // are tested when taking the pair of particle parent+child
+  // and child+parent.
+
+  // here are the tests entering the first series:
+  //  1. check if the cone is already inserted
+  //  2. check cone stability for the parent and child particles
+  
+  if (centre->side){
+    // test when both particles are not in the cone
+    // or when both are in.
+    // Note: for the totally exclusive case, test emptyness before
+    cone_candidate = cone;
+    if (cone.ref.not_empty()){
+      hc->insert(&cone_candidate, parent, child, false, false);
+    }
+
+    cone_candidate = cone;
+    cone_candidate+= *parent + *child;
+    hc->insert(&cone_candidate, parent, child, true, true);
+  } else {
+    // test when 1! of the particles is in the cone
+    cone_candidate = cone + *parent;
+    hc->insert(&cone_candidate, parent, child, true, false);
+
+    cone_candidate = cone + *child;
+    hc->insert(&cone_candidate, parent, child, false, true);
+  }
+
+  nb_tot+=2;
+
+  return 0;
+}
+
+
+/*
+ * update the cone
+ * go to the next child for that parent and update 'cone' appropriately
+ * return 0 if update candidate found, 1 otherwise
+ ***********************************************************************/
+int Cstable_cones::update_cone(){
+  // get the next child and centre
+  centre_idx++;
+  if (centre_idx==vicinity_size)
+    centre_idx=0;
+  if (centre_idx==first_cone)
+    return 1;
+
+  // update the cone w.r.t. the old child
+  // only required if the old child is entering inside in which
+  // case we need to add it. We also know that the child is 
+  // inside iff its side is -.
+  if (!centre->side){
+    // update cone
+    cone += (*child);
+
+    // update info on particles inside
+    centre->is_inside->cone = true;
+
+    // update stability check quantities
+    dpt += fabs(child->px)+fabs(child->py);
+  }
+
+  // update centre and child to correspond to the new position
+  centre = vicinity[centre_idx];
+  child = centre->v;
+
+  // check cocircularity
+  // note that if cocirculaity is detected (i.e. if we receive 1
+  // in the next test), we need to recall 'update_cone' directly
+  // since tests and remaining part of te update has been performed
+  //if (cocircular_check())
+  if (cocircular_check())
+    return update_cone();
+
+
+  // update the cone w.r.t. the new child
+  // only required if the new child was already inside in which
+  // case we need to remove it. We also know that the child is 
+  // inside iff its side is +.
+  if ((centre->side) && (cone.ref.not_empty())){
+    // update cone
+    cone -= (*child);
+
+    // update info on particles inside
+    centre->is_inside->cone = false;
+
+    // update stability check quantities
+    dpt += fabs(child->px)+fabs(child->py); //child->perp2();
+  }
+
+  // check that the addition and subtraction of vectors does
+  // not lead to too much rounding error
+  // for that, we compute the sum of pt modifications and of |pt|
+  // since last recomputation and once the ratio overpasses a threshold
+  // we recompute vicinity.
+  if ((dpt>PT_TSHOLD*(fabs(cone.px)+fabs(cone.py))) && (cone.ref.not_empty())){
+    recompute_cone_contents();
+  }
+  if (cone.ref.is_empty()){
+    cone = Cmomentum();
+    dpt=0.0;
+  }
+
+  return 0; 
+}
+
+
+/*
+ * compute stability of all enumerated candidates.
+ * For all candidate cones which are stable w.r.t. their border particles,
+ * pass the last test: stability with quadtree intersection
+ ************************************************************************/
+int Cstable_cones::proceed_with_stability(){
+  int i,n;
+  hash_element *elm;
+
+  n=0;
+  for (i=0;i<=hc->mask;i++){
+    // test ith cell of the hash array
+    elm = hc->hash_array[i];
+
+    // browse elements therein
+    while (elm!=NULL){
+      // test stability
+      if (elm->is_stable){
+	// stability is not ensured by all pairs of "edges" already browsed
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+	//  => testing stability with quadtree intersection
+	if (quadtree->circle_intersect(elm->eta, elm->phi, R2)==elm->ref)
+#else
+	//  => testing stability with the particle-list intersection
+	if (circle_intersect(elm->eta, elm->phi)==elm->ref)
+#endif
+	  protocones.push_back(Cmomentum(elm->eta, elm->phi, elm->ref));
+      }
+      
+      // jump to the next one
+      elm = elm->next;
+    }
+  }
+  
+  // free hash
+  // we do that at this level because hash eats rather a lot of memory
+  // we want to free it before running the split/merge algorithm
+  delete hc;
+  hc=NULL;
+
+  return protocones.size();
+}
+
+
+////////////////////////////////////////////////////////
+// ALGORITHM MAIN STEPS FOR COCIRCULAR SITUATIONS     //
+//  - cocircular_pt_less(v1, v2)                      //
+//  - prepare_cocircular_list()                       //
+//  - test_cone_cocircular()                          //
+//  - test_stability(candidate, border_vect)          //
+//  - updat_cone_cocircular()                         //
+////////////////////////////////////////////////////////
+
+/// pt-ordering of momenta used for the cocircular case
+bool cocircular_pt_less(Cmomentum *v1, Cmomentum *v2){
+  return v1->perp2() < v2->perp2();
+}
+
+/*
+ * run through the vicinity of the current parent and for each child
+ * establish which other members are cocircular... Note that the list
+ * associated with each child contains references to vicinity
+ * elements: thus two vicinity elements each associated with one given
+ * particle may appear in a list -- this needs to be watched out for
+ * later on... 
+ **********************************************************************/
+void Cstable_cones::prepare_cocircular_lists() {
+  circulator<vector<Cvicinity_elm*>::iterator > here(vicinity.begin(), 
+                                                     vicinity.begin(), 
+                                                     vicinity.end());
+
+  circulator<vector<Cvicinity_elm*>::iterator > search(here);
+
+  do {
+    Cvicinity_elm* here_pntr = *here();
+    search.set_position(here);
+
+    // search forwards for things that should have "here" included in
+    // their cocircularity list
+    while (true) {
+      ++search;
+      if ( abs_dphi((*search())->angle, here_pntr->angle) < 
+                                 here_pntr->cocircular_range 
+           && search() != here()) {
+        (*search())->cocircular.push_back(here_pntr);
+      } else {
+        break;
+      }
+    }
+
+    // search backwards
+    search.set_position(here);
+    while (true) {
+      --search;
+      if ( abs_dphi((*search())->angle, here_pntr->angle) < 
+                                 here_pntr->cocircular_range 
+           && search() != here()) {
+        (*search())->cocircular.push_back(here_pntr);
+      } else {
+        break;
+      }
+    }
+
+    ++here;
+  } while (here() != vicinity.begin());
+
+}
+
+/* 
+ * Testing cocircular configurations in p^3 time,
+ * rather than 2^p time; we will test all contiguous subsets of points
+ * on the border --- note that this is till probably overkill, since
+ * in principle we only have to test situations where up to a
+ * half-circle is filled (but going to a full circle is simpler)
+ ******************************************************************/
+void Cstable_cones::test_cone_cocircular(Cmomentum & borderless_cone,
+					 list<Cmomentum *> & border_list) {
+  vector<Cborder_store> border_vect;
+
+  border_vect.reserve(border_list.size());
+  for (list<Cmomentum *>::iterator it = border_list.begin();
+       it != border_list.end(); it++) {
+    border_vect.push_back(Cborder_store(*it, centre->eta, centre->phi));
+  }
+
+  // get them into order of angle
+  sort(border_vect.begin(), border_vect.end());
+
+  // set up some circulators, since these will help us go around the
+  // circle easily
+  circulator<vector<Cborder_store>::iterator > 
+    start(border_vect.begin(), border_vect.begin(),border_vect.end());
+  circulator<vector<Cborder_store>::iterator > mid(start), end(start);
+  
+  // test the borderless cone
+  Cmomentum candidate = borderless_cone;
+  candidate.build_etaphi();
+  if (candidate.ref.not_empty())
+    test_stability(candidate, border_vect);
+
+  do {
+    // reset status wrt inclusion in the cone
+    mid = start;
+    do {
+      mid()->is_in = false;
+    } while (++mid != start);
+
+    // now run over all inclusion possibilities with this starting point
+    candidate = borderless_cone;
+    while (++mid != start) { 
+      // will begin with start+1 and go up to start-1
+      mid()->is_in = true;
+      candidate += *(mid()->mom);
+      test_stability(candidate, border_vect);
+    }
+
+  } while (++start != end);
+
+  // mid corresponds to momentum that we need to include to get the
+  // full cone
+  mid()->is_in = true;
+  candidate += *(mid()->mom);
+  test_stability(candidate, border_vect);
+}
+
+
+/**
+ * carry out the computations needed for the stability check of the
+ * candidate, using the border_vect to indicate which particles
+ * should / should not be in the stable cone; if the cone is stable
+ * insert it into the hash.
+ **********************************************************************/
+void Cstable_cones::test_stability(Cmomentum & candidate, const vector<Cborder_store> & border_vect) {
+  
+  // this almost certainly has not been done...
+  candidate.build_etaphi();
+
+  bool stable = true;
+  for (unsigned i = 0; i < border_vect.size(); i++) {
+    if (is_inside(&candidate, border_vect[i].mom) ^ (border_vect[i].is_in)) {
+      stable = false;
+      break; // it's unstable so there's no point continuing
+    }
+  }
+
+  if (stable) hc->insert(&candidate);
+}
+
+/*
+ * check if we are in a situation of cocircularity.
+ * if it is the case, update and test in the corresponding way
+ * return 'false' if no cocircularity detected, 'true' otherwise
+ * Note that if cocircularity is detected, we need to 
+ * recall 'update' from 'update' !!!
+ ***************************************************************/
+bool Cstable_cones::cocircular_check(){
+  // check if many configurations have the same centre.
+  // if this is the case, branch on the algorithm for this
+  // special case.
+  // Note that those situation, being considered separately in 
+  // test_cone_multiple, must only be considered here if all
+  // angles are on the same side (this avoid multiple counting)
+
+  if (centre->cocircular.empty()) return false;
+
+  // first get cone into status required at end...
+  if ((centre->side) && (cone.ref.not_empty())){
+    // update cone
+    cone -= (*child);
+
+    // update info on particles inside
+    centre->is_inside->cone = false;
+
+    // update stability check quantities
+    dpt += fabs(child->px)+fabs(child->py); //child->perp2();
+  }
+
+
+  // now establish the list of unique children in the list
+  // first make sure parent and child are in!
+
+  list<Cvicinity_inclusion *> removed_from_cone;
+  list<Cvicinity_inclusion *> put_in_border;
+  list<Cmomentum *> border_list;
+  
+  Cmomentum cone_removal;
+  Cmomentum border = *parent;
+  border_list.push_back(parent);
+
+  // make sure child appears in the border region
+  centre->cocircular.push_back(centre);
+
+  // now establish the full contents of the cone minus the cocircular
+  // region and of the cocircular region itself
+  for(list<Cvicinity_elm *>::iterator it = centre->cocircular.begin();
+      it != centre->cocircular.end(); it++) {
+
+    if ((*it)->is_inside->cone) {
+      cone_removal           += *((*it)->v);
+      (*it)->is_inside->cone  = false;
+      removed_from_cone.push_back((*it)->is_inside);
+    }
+
+    // if a point appears twice (i.e. with + and - sign) in the list of 
+    // points on the border, we take care not to include it twice.
+    // Note that this situation may appear when a point is at a distance
+    // close to 2R from the parent
+    if (!(*it)->is_inside->cocirc) {
+      border += *((*it)->v);
+      (*it)->is_inside->cocirc  = true;
+      put_in_border.push_back((*it)->is_inside);
+      border_list.push_back((*it)->v);
+    }
+  }
+
+
+  // figure out whether this pairing has been observed before
+  Cmomentum borderless_cone = cone;
+  borderless_cone -= cone_removal;
+  bool consider = true;
+  for (unsigned int i=0;i<multiple_centre_done.size();i++){
+    if ((multiple_centre_done[i].first ==borderless_cone.ref) &&
+	(multiple_centre_done[i].second==border.ref))
+      consider = false;
+  }
+
+  // now prepare the hard work
+  if (consider) {
+    // record the fact that we've now seen this combination
+    multiple_centre_done.push_back(pair<Creference,Creference>(borderless_cone.ref, 
+                                                               border.ref));
+
+    // first figure out whether our cone momentum is good
+    double local_dpt = fabs(cone_removal.px) + fabs(cone_removal.py);
+    double total_dpt = dpt + local_dpt;
+
+    recompute_cone_contents_if_needed(borderless_cone, total_dpt);
+    if (total_dpt == 0) {
+      // a recomputation has taken place -- so take advantage of this
+      // and update the member cone momentum
+      cone = borderless_cone + cone_removal;
+      dpt  = local_dpt;
+    }
+
+    test_cone_cocircular(borderless_cone, border_list);
+  }
+
+
+  // relabel things that were in the cone but got removed
+  for(list<Cvicinity_inclusion *>::iterator is_in = removed_from_cone.begin();
+      is_in != removed_from_cone.end(); is_in++) {
+    (*is_in)->cone = true;
+  }
+
+  // relabel things that got put into the border 
+  for(list<Cvicinity_inclusion *>::iterator is_in = put_in_border.begin();
+      is_in != put_in_border.end(); is_in++) {
+    (*is_in)->cocirc = false;
+  }
+
+  // we're done with everything -- return true to signal to user that we've
+  // been through the co-circularity rigmarole
+  return true;
+}
+
+
+////////////////////////////////////////////////////////
+// RECOMPUTATION OF CONE CONTENTS                     //
+//  - compute_cone_contents()                         //
+//  - recompute_cone_contents()                       //
+//  - recompute_cone_contents_if_needed()             //
+////////////////////////////////////////////////////////
+
+/**
+ * compute the cone contents by going once around the full set of
+ * circles and tracking the entry/exit status each time 
+ * given parent, child and centre compute the momentum
+ * of the particle inside the cone
+ * This sets up the inclusion information, which can then be directly 
+ * used to calculate the cone momentum.
+ **********************************************************************/
+void Cstable_cones::compute_cone_contents() {
+  circulator<vector<Cvicinity_elm*>::iterator > 
+    start(vicinity.begin()+first_cone, vicinity.begin(), vicinity.end());
+
+  circulator<vector<Cvicinity_elm*>::iterator > here(start);
+
+  // note that in the following algorithm, the cone contents never includes
+  // the child. Indeed, if it has positive sign, then it will be set as
+  // outside at the last step in the loop. If it has negative sign, then the 
+  // loop will at some point go to the corresponding situation with positive
+  // sign and set the inclusion status to 0.
+
+  do {
+    // as we leave this position a particle enters if its side is
+    // negative (i.e. the centre is the one at -ve angle wrt to the
+    // parent-child line
+    if (!(*here())->side) ((*here())->is_inside->cone) = 1;
+    
+    // move on to the next position
+    ++here;
+    
+    // as we arrive at this position a particle leaves if its side is positive
+    if ((*here())->side) ((*here())->is_inside->cone) = 0;
+  } while (here != start);
+
+  // once we've reached the start the 'is_inside' information should be
+  // 100% complete, so we can use it to calculate the cone contents
+  // and then exit
+  recompute_cone_contents();
+  return;
+
+}
+
+
+/*
+ * compute the cone momentum from particle list.
+ * in this version, we use the 'pincluded' information
+ * from the Cvicinity class
+ */
+void Cstable_cones::recompute_cone_contents(){
+  unsigned int i;
+
+  // set momentum to 0
+  cone = Cmomentum();
+
+  // Important note: we can browse only the particles
+  // in vicinity since all particles in the cone are
+  // withing a distance 2R w.r.t. parent hence in vicinity.
+  // Among those, we only add the particles for which 'is_inside' is true !
+  // This methos rather than a direct comparison avoids rounding errors
+  for (i=0;i<vicinity_size;i++){
+    // to avoid double-counting, only use particles with + angle
+    if ((vicinity[i]->side) && (vicinity[i]->is_inside->cone))
+      cone += *vicinity[i]->v;
+  }
+  
+  // set check variables back to 0
+  dpt = 0.0;
+}
+
+
+/*
+ * if we have gone beyond the acceptable threshold of change, compute
+ * the cone momentum from particle list.  in this version, we use the
+ * 'pincluded' information from the Cvicinity class, but we don't
+ * change the member cone, only the locally supplied one
+ */
+void Cstable_cones::recompute_cone_contents_if_needed(Cmomentum & this_cone, 
+                                                      double & this_dpt){
+  
+  if (this_dpt > PT_TSHOLD*(fabs(this_cone.px)+fabs(this_cone.py))) {
+    if (cone.ref.is_empty()) {
+      this_cone = Cmomentum();
+    } else {
+      // set momentum to 0
+      this_cone = Cmomentum();
+      
+      // Important note: we can browse only the particles
+      // in vicinity since all particles in the this_cone are
+      // withing a distance 2R w.r.t. parent hence in vicinity.
+      // Among those, we only add the particles for which 'is_inside' is true !
+      // This methos rather than a direct comparison avoids rounding errors
+      for (unsigned int i=0;i<vicinity_size;i++){
+        // to avoid double-counting, only use particles with + angle
+        if ((vicinity[i]->side) && (vicinity[i]->is_inside->cone))
+          this_cone += *vicinity[i]->v;
+      }
+      
+    }
+    // set check variables back to 0
+    this_dpt = 0.0;
+  }
+
+}
+
+
+////////////////////////////////////////////////////////
+// VARIOUS TOOLS                                      //
+//  - circle_intersect()                              //
+//  - is_inside()                                     //
+//  - abs_dangle()                                    //
+////////////////////////////////////////////////////////
+
+
+/*
+ * circle intersection.
+ * computes the intersection with a circle of given centre and radius.
+ * The output takes the form of a checkxor of the intersection's particles
+ *  - cx    circle centre x coordinate
+ *  - cy    circle centre y coordinate
+ * return the checkxor for the intersection
+ ******************************************************************/
+Creference Cstable_cones::circle_intersect(double cx, double cy){
+  Creference intersection;
+  int i;
+  double dx, dy;
+
+  for (i=0;i<n_part;i++){
+    // compute the distance of the i-th particle with the parent
+    dx = plist[i].eta - cx;
+    dy = fabs(plist[i].phi - cy);
+    
+    // pay attention to the periodicity in phi !
+    if (dy>M_PI) 
+      dy -= twopi;
+    
+    // really check if the distance is less than VR
+    if (dx*dx+dy*dy<R2)
+      intersection+=plist[i].ref;
+  }
+  
+  return intersection;
+}
+
+/*
+ * test if a particle is inside a cone of given centre.
+ * check if the particle of coordinates 'v' is inside the circle of radius R 
+ * centered at 'centre'.
+ *  - centre   centre of the circle
+ *  - v        particle to test
+ * return true if inside, false if outside
+ *****************************************************************************/
+inline bool Cstable_cones::is_inside(Cmomentum *centre, Cmomentum *v){
+  double dx, dy;
+
+  dx = centre->eta - v->eta;
+  dy = fabs(centre->phi - v->phi);
+  if (dy>M_PI) 
+    dy -= twopi;
+      
+  return dx*dx+dy*dy<R2;
+}
+
+/*
+ * compute the absolute value of the difference between 2 angles.
+ * We take care of the 2pi periodicity
+ *  - angle1   first angle
+ *  - angle2   second angle
+ * return the absolute value of the difference between the angles
+ *****************************************************************/
+inline double abs_dangle(double &angle1, double &angle2){
+  double dphi;
+
+  dphi = fabs(angle1-angle2);
+  if (dphi>M_PI) 
+    dphi = dphi-twopi;
+      
+  return dphi;
+}
+  
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/quadtree.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/quadtree.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/quadtree.cc	(revision 11)
@@ -0,0 +1,304 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: quadtree.cpp                                                        //
+// Description: source file for quadtree management (Cquadtree class)        //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:12 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/quadtree.h"
+#include <math.h>
+#include <stdio.h>
+#include <iostream>
+
+namespace siscone{
+
+using namespace std;
+
+/*******************************************************************
+ * Cquadtree implementation                                        *
+ * Implementation of a 2D quadtree.                                *
+ * This class implements the traditional two-dimensional quadtree. *
+ * The elements at each node are of 'Cmomentum' type.              *
+ *******************************************************************/
+
+// default ctor
+//--------------
+Cquadtree::Cquadtree(){
+  v = NULL;
+
+  children[0][0] = children[0][1] = children[1][0] = children[1][1] = NULL;
+  has_child = false;
+}
+
+
+// ctor with initialisation (see init for details)
+//--------------------------
+Cquadtree::Cquadtree(double _x, double _y, double _half_size_x, double _half_size_y){
+  v = NULL;
+
+  children[0][0] = children[0][1] = children[1][0] = children[1][1] = NULL;
+  has_child = false;
+
+  init(_x, _y, _half_size_x, _half_size_y);
+}
+
+
+// default destructor
+// at destruction, everything is destroyed except 
+// physical values at the leaves
+//------------------------------------------------
+Cquadtree::~Cquadtree(){
+  if (has_child){
+    if (v!=NULL) delete v;
+    delete children[0][0];
+    delete children[0][1];
+    delete children[1][0];
+    delete children[1][1];
+  }
+}
+
+
+/*
+ * init the tree.
+ * By initializing the tree, we mean setting the cell parameters
+ * and preparing the object to act as a seed for a new tree.
+ *  - _x           x-position of the center
+ *  - _y           y-position of the center
+ *  - half_size_x  half x-size of the cell
+ *  - half_size_y  half y-size of the cell
+ * return 0 on success, 1 on error. Note that if the cell
+ *        is already filled, we return an error.
+ ******************************************************************/
+int Cquadtree::init(double _x, double _y, double _half_size_x, double _half_size_y){
+  if (v!=NULL)
+    return 1;
+
+  centre_x = _x;
+  centre_y = _y;
+  half_size_x = _half_size_x;
+  half_size_y = _half_size_y;
+
+  return 0;
+}
+
+
+/*
+ * adding a particle to the tree.
+ * This method adds one vector to the quadtree structure which 
+ * is updated consequently.
+ *  - v   vector to add
+ * return 0 on success 1 on error
+ ******************************************************************/
+int Cquadtree::add(Cmomentum *v_add){
+  // Description of the method:
+  // --------------------------
+  // the addition process goes as follows:
+  //  1. check if the cell is empty, in which case, add the particle 
+  //     here and leave.
+  //  2. If there is a unique particle already inside,
+  //      (a) create children
+  //      (b) forward the existing particle to the appropriate child
+  //  3. Add current particle to this cell and forward to the 
+  //     adequate child
+  // NOTE: we assume in the whole procedure that the particle is 
+  //       indeed inside the cell !
+
+  // step 1: the case of empty cells
+  if (v==NULL){
+    v = v_add;
+    return 0;
+  }
+
+  // step 2: additional work if 1! particle already present
+  //         we use the fact that only 1-particle systems have no child
+  if (!has_child){
+    double new_half_size_x = 0.5*half_size_x;
+    double new_half_size_y = 0.5*half_size_y;
+    // create children
+    children[0][0] = new Cquadtree(centre_x-new_half_size_x, centre_y-new_half_size_y,
+				   new_half_size_x, new_half_size_y);
+    children[0][1] = new Cquadtree(centre_x-new_half_size_x, centre_y+new_half_size_y,
+				   new_half_size_x, new_half_size_y);
+    children[1][0] = new Cquadtree(centre_x+new_half_size_x, centre_y-new_half_size_y,
+				   new_half_size_x, new_half_size_y);
+    children[1][1] = new Cquadtree(centre_x+new_half_size_x, centre_y+new_half_size_y,
+				   new_half_size_x, new_half_size_y);
+
+    has_child = true;
+
+    // forward to child
+    //? The following line assumes 'true'==1 and 'false'==0
+    // Note: v being a single particle, eta and phi are correct
+    children[v->eta>centre_x][v->phi>centre_y]->add(v);
+
+    // copy physical params
+    v = new Cmomentum(*v);
+  }
+
+  // step 3: add new particle
+  // Note: v_add being a single particle, eta and phi are correct
+  children[v_add->eta>centre_x][v_add->phi>centre_y]->add(v_add);
+  *v+=*v_add;
+
+  return 0;
+}
+
+
+/*
+ * circle intersection.
+ * computes the intersection with a circle of given centre and radius.
+ * The output takes the form of a quadtree with all squares included 
+ * in the circle.
+ *  - cx    circle centre x coordinate
+ *  - cy    circle centre y coordinate
+ *  - cR2   circle radius SQUARED
+ * return the checksum for the intersection
+ ******************************************************************/
+Creference Cquadtree::circle_intersect(double cx, double cy, double cR2){
+  // Description of the method:
+  // --------------------------
+  // 1. check if cell is empty => no intersection
+  // 2. if cell has 1! particle, check if it is inside the circle.
+  //    If yes, add it and return, if not simply return.
+  // 3. check if the circle intersects the square. If not, return.
+  // 4. check if the square is inside the circle. 
+  //    If yes, add it to qt and return.
+  // 5. check intersections with children.
+
+  // step 1: if there is no particle inside te square, no reason to go further
+  if (v==NULL)
+    return Creference();
+
+  double dx, dy;
+
+  // step 2: if there is only one particle inside the square, test if it is in
+  //         the circle, in which case return associated reference
+  if (!has_child){
+    // compute the distance
+    // Note: v has only one particle => eta and phi are defined
+    dx = cx - v->eta;
+    dy = fabs(cy - v->phi);
+    if (dy>M_PI) 
+      dy -= 2.0*M_PI;
+
+    // test distance
+    if (dx*dx+dy*dy<cR2){
+      return v->ref;
+    }
+
+    return Creference();
+  }
+
+  // step 3: check if there is an intersection
+  //double ryp, rym;
+  double dx_c, dy_c;
+
+  // store distance with the centre of the square
+  dx_c = fabs(cx-centre_x);
+  dy_c = fabs(cy-centre_y);
+  if (dy_c>M_PI) dy_c = 2.0*M_PI-dy_c;
+
+  // compute (minimal) the distance (pay attention to the periodicity in phi).
+  dx = dx_c-half_size_x;
+  if (dx<0) dx=0;
+  dy = dy_c-half_size_y;
+  if (dy<0) dy=0;
+
+  // check the distance 
+  if (dx*dx+dy*dy>=cR2){
+    // no intersection
+    return Creference();
+  }
+
+  // step 4: check if included
+
+  // compute the (maximal) distance
+  dx = dx_c+half_size_x;
+  dy = dy_c+half_size_y;
+  if (dy>M_PI) dy = M_PI;
+
+  // compute the distance
+  if (dx*dx+dy*dy<cR2){
+    return v->ref;
+  }
+
+  // step 5: the square is not fully in. Recurse to children
+  return children[0][0]->circle_intersect(cx, cy, cR2)
+    + children[0][1]->circle_intersect(cx, cy, cR2)
+    + children[1][0]->circle_intersect(cx, cy, cR2)
+    + children[1][1]->circle_intersect(cx, cy, cR2);
+}
+
+
+/*
+ * output a data file for drawing the grid.
+ * This can be used to output a data file containing all the
+ * grid subdivisions. The file contents is as follows:
+ * first and second columns give center of the cell, the third 
+ * gives the size.
+ *  - flux  opened stream to write to
+ * return 0 on success, 1 on error
+ ******************************************************************/
+int Cquadtree::save(FILE *flux){
+
+  if (flux==NULL)
+    return 1;
+
+  if (has_child){
+    fprintf(flux, "%le\t%le\t%le\t%le\n", centre_x, centre_y, half_size_x, half_size_y);
+    children[0][0]->save(flux);
+    children[0][1]->save(flux);
+    children[1][0]->save(flux);
+    children[1][1]->save(flux);
+  }
+
+  return 0;
+}
+
+
+/*
+ * output a data file for drawing the tree leaves.
+ * This can be used to output a data file containing all the
+ * tree leaves. The file contents is as follows:
+ * first and second columns give center of the cell, the third 
+ * gives the size.
+ *  - flux  opened stream to write to
+ * return 0 on success, 1 on error
+ ******************************************************************/
+int Cquadtree::save_leaves(FILE *flux){
+
+  if (flux==NULL)
+    return 1;
+
+  if (has_child){
+    if (children[0][0]!=NULL) children[0][0]->save_leaves(flux);
+    if (children[0][1]!=NULL) children[0][1]->save_leaves(flux);
+    if (children[1][0]!=NULL) children[1][0]->save_leaves(flux);
+    if (children[1][1]!=NULL) children[1][1]->save_leaves(flux);
+  } else {
+    fprintf(flux, "%le\t%le\t%le\t%le\n", centre_x, centre_y, half_size_x, half_size_y);
+  }
+
+  return 0;
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/ranlux.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/ranlux.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/ranlux.cc	(revision 11)
@@ -0,0 +1,171 @@
+// file: ranlux.xpp
+#include "../interface/ranlux.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* This is a lagged fibonacci generator with skipping developed by Luescher.
+   The sequence is a series of 24-bit integers, x_n, 
+
+   x_n = d_n + b_n
+
+   where d_n = x_{n-10} - x_{n-24} - c_{n-1}, b_n = 0 if d_n >= 0 and
+   b_n = 2^24 if d_n < 0, c_n = 0 if d_n >= 0 and c_n = 1 if d_n < 0,
+   where after 24 samples a group of p integers are "skipped", to
+   reduce correlations. By default p = 199, but can be increased to
+   365.
+
+   The period of the generator is around 10^171. 
+
+   From: M. Luescher, "A portable high-quality random number generator
+   for lattice field theory calculations", Computer Physics
+   Communications, 79 (1994) 100-110.
+
+   Available on the net as hep-lat/9309020 at http://xxx.lanl.gov/
+
+   See also,
+
+   F. James, "RANLUX: A Fortran implementation of the high-quality
+   pseudo-random number generator of Luscher", Computer Physics
+   Communications, 79 (1994) 111-114
+
+   Kenneth G. Hamilton, F. James, "Acceleration of RANLUX", Computer
+   Physics Communications, 101 (1997) 241-248
+
+   Kenneth G. Hamilton, "Assembler RANLUX for PCs", Computer Physics
+   Communications, 101 (1997) 249-253  */
+
+namespace siscone{
+
+static const unsigned long int mask_lo = 0x00ffffffUL;  // 2^24 - 1
+static const unsigned long int mask_hi = ~0x00ffffffUL;
+static const unsigned long int two24 = 16777216;        // 2^24
+
+
+// internal generator structure
+//------------------------------
+typedef struct {
+  unsigned int i;
+  unsigned int j;
+  unsigned int n;
+  unsigned int skip;
+  unsigned int carry;
+  unsigned long int u[24];
+} ranlux_state_t;
+
+
+// internal generator state
+//--------------------------
+ranlux_state_t local_ranlux_state;
+
+
+// incrementation of the generator state
+//---------------------------------------
+static inline unsigned long int increment_state(){
+  unsigned int i = local_ranlux_state.i;
+  unsigned int j = local_ranlux_state.j;
+  long int delta = local_ranlux_state.u[j] - local_ranlux_state.u[i] 
+    - local_ranlux_state.carry;
+
+  if (delta & mask_hi){
+    local_ranlux_state.carry = 1;
+    delta &= mask_lo;
+  } else {
+    local_ranlux_state.carry = 0;
+  }
+
+  local_ranlux_state.u[i] = delta;
+  
+  if (i==0)
+    i = 23;
+  else
+    i--;
+
+  local_ranlux_state.i = i;
+
+  if (j == 0)
+    j = 23;
+  else
+    j--;
+
+  local_ranlux_state.j = j;
+
+  return delta;
+}
+
+
+// set generator state
+//---------------------
+static void ranlux_set(unsigned long int s){
+  int i;
+  long int seed;
+  
+  if (s==0)
+    s = 314159265;      /* default seed is 314159265 */
+  
+  seed = s;
+  
+  /* This is the initialization algorithm of F. James, widely in use
+     for RANLUX. */
+
+  for (i=0;i<24;i++){
+    unsigned long int k = seed/53668;
+    seed = 40014*(seed-k*53668)-k*12211;
+    if (seed<0){
+      seed += 2147483563;
+    }
+    local_ranlux_state.u[i] = seed%two24;
+  }
+
+  local_ranlux_state.i = 23;
+  local_ranlux_state.j = 9;
+  local_ranlux_state.n = 0;
+  local_ranlux_state.skip = 389-24; // 389 => best decorrelation
+
+  if (local_ranlux_state.u[23]&mask_hi){
+    local_ranlux_state.carry = 1;
+  } else {
+    local_ranlux_state.carry = 0;
+  }
+}
+
+
+// generator initialization
+//--------------------------
+void ranlux_init(){
+  // seed the generator
+  ranlux_set(0);
+}
+
+
+// get random number
+//-------------------
+unsigned long int ranlux_get(){
+  const unsigned int skip = local_ranlux_state.skip;
+  unsigned long int r = increment_state();
+  
+  local_ranlux_state.n++;
+
+  if (local_ranlux_state.n == 24){
+    unsigned int i;
+    local_ranlux_state.n = 0;
+    for (i = 0; i < skip; i++)
+      increment_state();
+  }
+
+  return r;
+}
+
+// print generator state
+//-----------------------
+void ranlux_print_state(){
+  size_t i;
+  unsigned char *p = (unsigned char *) (&local_ranlux_state);
+  const size_t n = sizeof (ranlux_state_t);
+
+  for (i=0;i<n;i++){
+    /* FIXME: we're assuming that a char is 8 bits */
+    printf("%.2x", *(p+i));
+  }
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/reference.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/reference.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/reference.cc	(revision 11)
@@ -0,0 +1,127 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: reference.cpp                                                       //
+// Description: source file for checkxor management (Creference class)       //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:13 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/reference.h"
+#include "../interface/ranlux.h"
+#include <stdlib.h>
+
+namespace siscone{
+
+/*******************************************************
+ * Creference implementation                           *
+ * references used for checksums.                      *
+ *                                                     *
+ * This class implements some reference variable       *
+ * that can be used for checksums. Those checksums     *
+ * are useful to disentengle between contents of two   *
+ * cones without looking into their explicit particle  *
+ * contents.                                           *
+ *******************************************************/
+
+// default constructor
+//////////////////////
+Creference::Creference(){
+  ref[0] = ref[1] = ref[2] = 0;
+}
+
+  //static unsigned int reference_bit = 1;
+
+// create a random reference
+//---------------------------
+void Creference::randomize(){
+//  ref[0] = reference_bit;
+//  ref[1] = 0;
+//  ref[2] = 0;
+//  reference_bit <<= 1;
+
+  unsigned int r1 = ranlux_get();
+  unsigned int r2 = ranlux_get();
+  unsigned int r3 = ranlux_get();
+  unsigned int r4 = ranlux_get();
+  // since ranlux only produces 24 bits, take r4 and add 8 bits
+  // from it to each of r1,r2, r3 to get 3*32 bits.
+  ref[0] = r1+((r4 & 0x00ff0000) <<  8);
+  ref[1] = r2+((r4 & 0x0000ff00) << 16);
+  ref[2] = r3+((r4 & 0x000000ff) << 24);
+
+  if (is_empty()) randomize();
+}
+
+// test emptyness
+//----------------
+bool Creference::is_empty(){
+  return (ref[0]==0) && (ref[1]==0) && (ref[2]==0);
+}
+
+// test non-emptyness
+//--------------------
+bool Creference::not_empty(){
+  return (ref[0]!=0) || (ref[1]!=0) || (ref[2]!=0);
+}
+
+// assignment of reference
+//-------------------------
+Creference& Creference::operator = (const Creference &r){
+  ref[0] = r.ref[0];  
+  ref[1] = r.ref[1];
+  ref[2] = r.ref[2];
+  return *this;
+}
+
+// addition of reference
+//-----------------------
+Creference Creference::operator + (const Creference &r){
+  Creference tmp = *this;
+  return tmp+=r;
+}
+
+// incrementation of reference
+//-----------------------------
+Creference& Creference::operator += (const Creference &r){
+  ref[0] ^= r.ref[0];  
+  ref[1] ^= r.ref[1];
+  ref[2] ^= r.ref[2];
+  return *this; 
+}
+
+// decrementation of reference
+//-----------------------------
+Creference& Creference::operator -= (const Creference &r){
+  ref[0] ^= r.ref[0];  
+  ref[1] ^= r.ref[1];
+  ref[2] ^= r.ref[2];
+  return *this; 
+}
+
+// addition with 2 references
+//----------------------------
+Creference operator + (Creference &r1, Creference &r2){
+  Creference tmp = r1;
+  return r1+=r2;
+}
+
+}
+
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/siscone.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/siscone.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/siscone.cc	(revision 11)
@@ -0,0 +1,209 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: siscone.cpp                                                         //
+// Description: source file for the main SISCone class                       //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:13 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/config.h"
+
+#include "../interface/ranlux.h"
+#include "../interface/momentum.h"
+#include "../interface/defines.h"
+#include "../interface/siscone.h"
+#include "../interface/siscone_error.h"
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+namespace siscone{
+using namespace std;
+
+/***************************************************************
+ * Csiscone implementation                                     *
+ * final class: gather everything to compute the jet contents. *
+ *                                                             *
+ * This is the class user should use.                          *
+ * It computes the jet contents of a list of particles         *
+ * given a cone radius and a threshold for splitting/merging.  *
+ ***************************************************************/
+
+// default ctor
+//--------------
+Csiscone::Csiscone(){
+  rerun_allowed = false;
+}
+
+// default dtor
+//--------------
+Csiscone::~Csiscone(){
+  rerun_allowed = false;
+}
+
+bool Csiscone::init_done=false;
+
+/*
+ * compute the jets from a given particle set doing multiple passes
+ * such pass N looks for jets among all particles not put into jets
+ * during previous passes.
+ *  - _particles   list of particles
+ *  - _radius      cone radius
+ *  - _f           shared energy threshold for splitting&merging
+ *  - _n_pass_max  maximum number of runs
+ *  - _ptmin       minimum pT of the protojets
+ *  - _split_merge_scale    the scale choice for the split-merge procedure
+ *    NOTE: using pt leads to IR unsafety for some events with momentum
+ *          conservation. So we strongly advise not to change the default
+ *          value.
+ * return the number of jets found.
+ **********************************************************************/
+int Csiscone::compute_jets(vector<Cmomentum> &_particles, double _radius, double _f, 
+			   int _n_pass_max, double _ptmin,
+			   Esplit_merge_scale _split_merge_scale){
+  // initialise random number generator
+  if (!init_done){
+    // initialise random number generator
+    ranlux_init();
+
+    // print the banner
+    cout << "#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" << endl;
+    cout << "#                    SISCone   version " << setw(28) << left << siscone_version() << "o" << endl;
+    cout << "#              http://projects.hepforge.org/siscone                o" << endl;
+    cout << "#                                                                  o" << endl;
+    cout << "# This is SISCone: the Seedless Infrared Safe Cone Jet Algorithm   o" << endl;
+    cout << "# SISCone was written by Gavin Salam and Gregory Soyez             o" << endl;
+    cout << "# It is released under the terms of the GNU General Public License o" << endl;
+    cout << "#                                                                  o" << endl;
+    cout << "# A description of the algorithm is available in the publication   o" << endl;
+    cout << "# JHEP 05 (2007) 086 [arXiv:0704.0292 (hep-ph)].                   o" << endl;
+    cout << "# Please cite it if you use SISCone.                               o" << endl;
+    cout << "#ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" << endl;
+    cout << endl;
+    // do not do this again
+    init_done=true;
+  }
+
+  // run some general safety tests (NB: f will be checked in split-merge)
+  if (_radius <= 0.0 || _radius >= 0.5*M_PI) {
+    ostringstream message;
+    message << "Illegal value for cone radius, R = " << _radius 
+            << " (legal values are 0<R<pi/2)";
+    throw Csiscone_error(message.str());
+  }
+
+
+
+  ptcomparison.split_merge_scale = _split_merge_scale;
+  partial_clear(); // make sure some things are initialised properly
+
+  // init the split_merge algorithm with the initial list of particles
+  // this initialises particle list p_left of remaining particles to deal with
+  init_particles(_particles);
+
+  bool finished = false;
+
+  rerun_allowed = false;
+  protocones_list.clear();
+
+  do{
+    // initialise stable_cone finder
+    // here we use the list of remaining particles
+    // AFTER COLLINEAR CLUSTERING !!!!!!
+    Cstable_cones::init(p_uncol_hard);
+
+    // get stable cones
+    if (get_stable_cones(_radius)){
+      // we have some new protocones.
+      // add them to candidates
+      protocones_list.push_back(protocones);
+      add_protocones(&protocones, R2, _ptmin);
+    } else {
+      // no new protocone: leave
+      finished=true;
+    }
+
+    _n_pass_max--;
+  } while ((!finished) && (n_left>0) && (_n_pass_max!=0));
+
+  rerun_allowed = true;
+
+  // split & merge
+  return perform(_f, _ptmin);
+}
+
+/*
+ * recompute the jets with a different overlap parameter.
+ * we use the same particles and R as in the preceeding call.
+ *  - _f           shared energy threshold for splitting&merging
+ *  - _ptmin       minimum pT of the protojets
+ *  - _split_merge_scale    the scale choice for the split-merge procedure
+ *    NOTE: using pt leads to IR unsafety for some events with momentum
+ *          conservation. So we strongly advise not to change the default
+ *          value.
+ * return the number of jets found, -1 if recomputation not allowed.
+ ********************************************************************/
+int Csiscone::recompute_jets(double _f, double _ptmin,
+			     Esplit_merge_scale _split_merge_scale){
+  if (!rerun_allowed)
+    return -1;
+
+  ptcomparison.split_merge_scale = _split_merge_scale;
+
+  // restore particle list
+  partial_clear();
+  init_pleft();
+
+  // initialise split/merge algorithm
+  unsigned int i;
+  for (i=0;i<protocones_list.size();i++)
+    add_protocones(&(protocones_list[i]), R2, _ptmin);
+
+  // split & merge
+  return perform(_f, _ptmin);
+}  
+
+
+// finally, a bunch of functions to access to 
+// basic information (package name, version)
+//---------------------------------------------
+
+/* 
+ * return SISCone package name.
+ * This is nothing but "SISCone", it is a replacement to the
+ * PACKAGE_NAME string defined in config.h and which is not
+ * public by default.
+ * return the SISCone name as a string
+ */
+string siscone_package_name(){
+  return VERSION;
+}
+
+/* 
+ * return SISCone version number.
+ * return a string of the form "X.Y.Z" with possible additional tag
+ *        (alpha, beta, devel) to mention stability status
+ */
+string siscone_version(){
+  return VERSION;
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/siscone_error.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/siscone_error.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/siscone_error.cc	(revision 11)
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: siscone_error.cpp                                                   //
+// Description: source file for SISCone error messages (Csiscone_error)      //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:13 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/siscone_error.h"
+
+namespace siscone{
+
+bool Csiscone_error::m_print_errors = true;
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/split_merge.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/split_merge.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/split_merge.cc	(revision 11)
@@ -0,0 +1,1023 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: split_merge.cpp                                                     //
+// Description: source file for splitting/merging (contains the CJet class)  //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:13 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/split_merge.h"
+#include "../interface/siscone_error.h"
+#include "../interface/momentum.h"
+#include <math.h>
+#include <limits>   // for max
+#include <iostream>
+#include <algorithm>
+#include <sstream>
+#include <cassert>
+
+namespace siscone{
+
+using namespace std;
+
+/********************************************************
+ * class Cjet implementation                            *
+ * real Jet information.                                *
+ * This class contains information for one single jet.  *
+ * That is, first, its momentum carrying information    *
+ * about its centre and pT, and second, its particle    *
+ * contents                                             *
+ ********************************************************/
+// default ctor
+//--------------
+Cjet::Cjet(){
+  n = 0;
+  v = Cmomentum();
+  pt_tilde = 0.0;
+  sm_var2 = 0.0;
+}
+
+// default dtor
+//--------------
+Cjet::~Cjet(){
+
+}
+
+// ordering of jets in pt (e.g. used in final jets ordering)
+//-----------------------------------------------------------
+bool jets_pt_less(const Cjet &j1, const Cjet &j2){
+  return j1.v.perp2() > j2.v.perp2();
+}
+
+
+/********************************************************
+ * Csplit_merge_ptcomparison implementation             *
+ * This deals with the ordering of the jets candidates  *
+ ********************************************************/
+
+// odering of two jets
+// The variable of the ordering is pt or mt 
+// depending on 'split_merge_scale' choice
+//
+// with EPSILON_SPLITMERGE defined, this attempts to identify
+// delicate cases where two jets have identical momenta except for
+// softish particles -- the difference of pt's may not be correctly
+// identified normally and so lead to problems for the fate of the
+// softish particle.
+//
+// NB: there is a potential issue in momentum-conserving events,
+// whereby the harder of two jets becomes ill-defined when a soft
+// particle is emitted --- this may have a knock-on effect on
+// subsequent split-merge steps in cases with sufficiently large R
+// (but we don't know what the limit is...)
+//------------------------------------------------------------------
+bool Csplit_merge_ptcomparison::operator ()(const Cjet &jet1, const Cjet &jet2) const{
+  double q1, q2;
+
+  // compute the value for comparison for both jets
+  // This depends on the choice of variable (mt is the default)
+  q1 = jet1.sm_var2;
+  q2 = jet2.sm_var2;
+
+  bool res = q1 > q2;
+
+  // if we enable the refined version of the comparison (see defines.h),
+  // we compute the difference more precisely when the two jets are very
+  // close in the ordering variable.
+#ifdef EPSILON_SPLITMERGE
+  if ( (fabs(q1-q2) < EPSILON_SPLITMERGE*max(q1,q2)) &&
+       (jet1.v.ref != jet2.v.ref) ) {
+    // get the momentum of the difference
+    Cmomentum difference;
+    double pt_tilde_difference;
+    get_difference(jet1,jet2,&difference,&pt_tilde_difference);
+    
+    // use the following relation: pt1^2 - pt2^2 = (pt1+pt2)*(pt1-pt2)
+    double qdiff;
+    Cmomentum sum = jet1.v ;
+    sum +=  jet2.v;
+    double pt_tilde_sum = jet1.pt_tilde + jet2.pt_tilde;
+    
+    // depending on the choice of ordering variable, set the result
+    switch (split_merge_scale){
+    case SM_mt:
+      qdiff = sum.E*difference.E - sum.pz*difference.pz;
+      break;
+    case SM_pt:
+      qdiff = sum.px*difference.px + sum.py*difference.py;
+      break;
+    case SM_pttilde:  
+      qdiff = pt_tilde_sum*pt_tilde_difference;
+      break;
+    case SM_Et:
+      // diff = E^2 (dpt^2 pz^2- pt^2 dpz^2)
+      //      + dE^2 (pt^2+pz^2) pt2^2
+      // where, unless explicitely specified the variables
+      // refer to the first jet or differences jet1-jet2.
+      qdiff = jet1.v.E*jet1.v.E*
+	((sum.px*difference.px + sum.py*difference.py)*jet1.v.pz*jet1.v.pz
+	 -jet1.v.perp2()*sum.pz*difference.pz)
+	+sum.E*difference.E*(jet1.v.perp2()+jet1.v.pz*jet1.v.pz)*jet2.v.perp2();
+      break;
+    default:
+      throw Csiscone_error("Unsupported split-merge scale choice: "
+			   + SM_scale_name());
+    }
+    res = qdiff > 0;
+  }
+#endif  // EPSILON_SPLITMERGE
+
+  return res;
+}
+
+
+/// return a name for the sm scale choice 
+/// NB: used internally and also by fastjet
+std::string split_merge_scale_name(Esplit_merge_scale sms) {
+  switch(sms) {
+  case SM_pt:
+    return "pt (IR unsafe)";
+  case SM_Et:
+    return "Et (boost dep.)";
+  case SM_mt:
+    return "mt (IR safe except for pairs of identical decayed heavy particles)";
+  case SM_pttilde:
+    return "pttilde (scalar sum of pt's)";
+  default:
+    return "[SM scale without a name]";
+  }
+}
+
+
+// get the difference between 2 jets
+//  - j1         first jet
+//  - j2         second jet
+//  - v          jet1-jet2
+//  - pt_tilde   jet1-jet2 pt_tilde
+// return true if overlapping, false if disjoint
+//-----------------------------------------------
+void Csplit_merge_ptcomparison::get_difference(const Cjet &j1, const Cjet &j2, Cmomentum *v, double *pt_tilde) const {
+  int i1,i2;
+
+  // initialise
+  i1=i2=0;
+  *v = Cmomentum();
+  *pt_tilde = 0.0;
+
+  // compute overlap
+  // at the same time, we store union in indices
+  do{
+    if (j1.contents[i1]==j2.contents[i2]) {
+      i1++;
+      i2++;
+    } else if (j1.contents[i1]<j2.contents[i2]){
+      (*v) += (*particles)[j1.contents[i1]];
+      (*pt_tilde) += (*pt)[j1.contents[i1]];
+      i1++;
+    } else if (j1.contents[i1]>j2.contents[i2]){
+      (*v) -= (*particles)[j2.contents[i2]];
+      (*pt_tilde) -= (*pt)[j2.contents[i2]];
+      i2++;
+    } else {
+      throw Csiscone_error("get_non_overlap reached part it should never have seen...");
+    }
+  } while ((i1<j1.n) && (i2<j2.n));
+
+  // deal with particles at the end of the list...
+  while (i1 < j1.n) {
+    (*v) += (*particles)[j1.contents[i1]];
+    (*pt_tilde) += (*pt)[j1.contents[i1]];
+    i1++;
+  }
+  while (i2 < j2.n) {
+    (*v) -= (*particles)[j2.contents[i2]];
+    (*pt_tilde) -= (*pt)[j2.contents[i2]];
+    i2++;
+  }
+}
+
+
+/********************************************************
+ * class Csplit_merge implementation                    *
+ * Class used to split and merge jets.                  *
+ ********************************************************/
+// default ctor
+//--------------
+Csplit_merge::Csplit_merge(){
+  merge_identical_protocones = false;
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+#ifdef MERGE_IDENTICAL_PROTOCONES_DEFAULT_TRUE
+  merge_identical_protocones = true;
+#endif
+#endif
+  indices = NULL;
+
+  // ensure that ptcomparison points to our set of particles (though params not correct)
+  ptcomparison.particles = &particles;
+  ptcomparison.pt = &pt;
+  candidates.reset(new multiset<Cjet,Csplit_merge_ptcomparison>(ptcomparison));
+
+  // no hardest cut (col-unsafe)
+  SM_var2_hardest_cut_off = -1.0;
+
+  // no pt cutoff for the particles to put in p_uncol_hard
+  stable_cone_soft_pt2_cutoff = -1.0;
+}
+
+
+// default dtor
+//--------------
+Csplit_merge::~Csplit_merge(){
+  full_clear();
+}
+
+
+// initialisation function
+//  - _particles  list of particles
+//  - protocones  list of protocones (initial jet candidates)
+//  - R2          cone radius (squared)
+//  - ptmin       minimal pT allowed for jets
+//-------------------------------------------------------------
+int Csplit_merge::init(vector<Cmomentum> &_particles, vector<Cmomentum> *protocones, double R2, double ptmin){
+  // browse protocones
+  return add_protocones(protocones, R2, ptmin);
+}
+
+
+// initialisation function for particle list
+//  - _particles  list of particles
+//-------------------------------------------------------------
+int Csplit_merge::init_particles(vector<Cmomentum> &_particles){
+  full_clear();
+
+  // compute the list of particles
+  // here, we do not need to throw away particles 
+  // with infinite rapidity (colinear with the beam)
+  particles = _particles;
+  n = particles.size();
+
+  // build the vector of particles' pt and determine min,max eta
+  double eta_min=0.0;  /// for the Ceta_phi_range static member!
+  double eta_max=0.0;  /// for the Ceta_phi_range static member!
+  pt.resize(n);
+  for (int i=0;i<n;i++){
+    pt[i] = particles[i].perp();
+    eta_min = min(eta_min, particles[i].eta);
+    eta_max = max(eta_max, particles[i].eta);
+  }
+  Ceta_phi_range epr;
+  epr.eta_min = eta_min-0.01;
+  epr.eta_max = eta_max+0.01;
+
+  // ensure that ptcomparison points to our set of particles (though params not correct)
+  ptcomparison.particles = &particles;
+  ptcomparison.pt = &pt;
+
+  // set up the list of particles left.
+  init_pleft();
+
+  indices = new int[n];
+
+  return 0;
+}
+
+
+// build initial list of remaining particles
+//------------------------------------------
+int Csplit_merge::init_pleft(){
+  // at this level, we only rule out particles with 
+  // infinite rapidity
+  // in the parent particle list, index contain the run 
+  // at which particles are puts in jets:
+  //  - -1 means infinity rapidity
+  //  -  0 means not included
+  //  -  i mean included at run i
+  int i,j;
+
+  // copy particles removing the ones with infinite rapidity
+  j=0;
+  p_remain.clear();
+  for (i=0;i<n;i++){
+    // set ref for checkxor
+    particles[i].ref.randomize();
+
+    // check if rapidity is not infinite or ill-defined
+    if (fabs(particles[i].pz) < (particles[i].E)){
+      p_remain.push_back(particles[i]);
+      // set up parent index for tracability
+      p_remain[j].parent_index = i;
+      // left particles are marked with a 1
+      // IMPORTANT NOTE: the meaning of index in p_remain is
+      //   somehow different as in the initial particle list.
+      //   here, within one pass, we use the index to track whether
+      //   a particle is included in the current pass (index set to 0
+      //   in add_protocones) or still remain (index still 1)
+      p_remain[j].index = 1;
+
+      j++;
+      // set up parent-particle index
+      particles[i].index = 0;
+    } else {
+      particles[i].index = -1;
+    }
+  }
+  n_left = p_remain.size();
+  n_pass = 0;
+
+  merge_collinear_and_remove_soft();
+
+  return 0;
+}
+
+
+// partial clearance
+// we want to keep   particle list and indices
+// for future usage, so do not clear it !
+// this is done in full_clear
+//----------------------------------------
+int Csplit_merge::partial_clear(){
+  // release jets
+
+  // set up the auto_ptr for the multiset with the _current_ state of
+  // ptcomparison (which may have changed since we constructed the
+  // class)
+  candidates.reset(new multiset<Cjet,Csplit_merge_ptcomparison>(ptcomparison));
+
+  // start off with huge number
+  most_ambiguous_split = numeric_limits<double>::max();
+
+  jets.clear();
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+  if (merge_identical_protocones)
+    cand_refs.clear();
+#endif
+
+  p_remain.clear();
+
+  return 0;
+}
+
+
+// full clearance
+//----------------
+int Csplit_merge::full_clear(){
+  partial_clear();
+
+  // clear previously allocated memory
+  if (indices != NULL){
+    delete[] indices;
+  }
+  particles.clear();
+
+  return 0;
+}
+
+
+// build the list 'p_uncol_hard' from p_remain by clustering collinear particles
+// note that thins in only used for stable-cone detection 
+// so the parent_index field is unnecessary
+//-------------------------------------------------------------------------
+int Csplit_merge::merge_collinear_and_remove_soft(){
+  int i,j;
+  vector<Cmomentum> p_sorted;
+  bool collinear;
+  double dphi;
+
+  p_uncol_hard.clear();
+
+  // we first sort the particles according to their rapidity
+  for (i=0;i<n_left;i++)
+    p_sorted.push_back(p_remain[i]);
+  sort(p_sorted.begin(), p_sorted.end(), momentum_eta_less);
+
+  // then we cluster particles looping over the particles in the following way
+  // if (a particle i has same eta-phi a one after (j))
+  // then add momentum i to j
+  // else add i to the p_uncol_hard list
+  i = 0;
+  while (i<n_left){
+    // check if the particle passes the stable_cone_soft_pt2_cutoff
+    if (p_sorted[i].perp2()<stable_cone_soft_pt2_cutoff) {
+      i++;
+      continue;
+    }
+
+    // check if there is(are) particle(s) with the 'same' eta
+    collinear = false;
+    j=i+1;
+    while ((j<n_left) && (fabs(p_sorted[j].eta-p_sorted[i].eta)<EPSILON_COLLINEAR) && (!collinear)){
+      dphi = fabs(p_sorted[j].phi-p_sorted[i].phi);
+      if (dphi>M_PI) dphi = twopi-dphi;
+      if (dphi<EPSILON_COLLINEAR){
+	// i is collinear with j; add the momentum (i) to the momentum (j) 
+	p_sorted[j] += p_sorted[i];
+	// set collinearity test to true
+	collinear = true;
+      }
+      j++;
+    }
+    // if no collinearity detected, add the particle to our list
+    if (!collinear)
+      p_uncol_hard.push_back(p_sorted[i]);
+    i++;
+  }
+
+  return 0;
+}
+
+
+// add a list of protocones
+//  - protocones  list of protocones (initial jet candidates)
+//  - R2          cone radius (squared)
+//  - ptmin       minimal pT allowed for jets
+//-------------------------------------------------------------
+int Csplit_merge::add_protocones(vector<Cmomentum> *protocones, double R2, double ptmin){
+  int i;
+  Cmomentum *c;
+  Cmomentum *v;
+  double eta, phi;
+  double dx, dy;
+  double R;
+  Cjet jet;
+
+  if (protocones->size()==0)
+    return 1;
+
+  pt_min2 = ptmin*ptmin;
+  R = sqrt(R2);
+
+  // browse protocones
+  // for each of them, build the list of particles in them
+  for (vector<Cmomentum>::iterator p_it = protocones->begin();p_it != protocones->end();p_it++){
+    // initialise variables
+    c = &(*p_it);
+
+    // note: cones have been tested => their (eta,phi) coordinates are computed
+    eta = c->eta;
+    phi = c->phi;
+
+    // browse particles to create cone contents
+    // note that jet is always initialised with default values at this level
+    jet.v = Cmomentum();
+    jet.pt_tilde=0;
+    jet.contents.clear();
+    for (i=0;i<n_left;i++){
+      v = &(p_remain[i]);
+      // for security, avoid including particles with infinite rapidity)
+      // NO NEEDED ANYMORE SINCE REMOVED FROM p_remain FROM THE BEGINNING
+      //if (fabs(v->pz)!=v->E){
+      dx = eta - v->eta;
+      dy = fabs(phi - v->phi);
+      if (dy>M_PI) 
+	dy -= twopi;
+      if (dx*dx+dy*dy<R2){
+	jet.contents.push_back(v->parent_index);
+	jet.v+= *v;
+	jet.pt_tilde+= pt[v->parent_index];
+	v->index=0;
+      }
+    }
+    jet.n=jet.contents.size();
+
+    // set the momentum in protocones 
+    // (it was only known through eta and phi up to now)
+    *c = jet.v;
+    c->eta = eta; // restore exact original coords
+    c->phi = phi; // to avoid rounding error inconsistencies
+
+    // set the jet range
+    jet.range=Ceta_phi_range(eta,phi,R);
+
+#ifdef DEBUG_SPLIT_MERGE
+    cout << "adding jet: ";
+    for (int i2=0;i2<jet.n;i2++)
+      cout << jet.contents[i2] << " ";
+    cout << endl;
+#endif
+
+    // add it to the list of jets
+    insert(jet);
+  }
+  
+  // update list of included particles
+  n_pass++;
+
+#ifdef DEBUG_SPLIT_MERGE
+  cout << "remaining particles: "; 
+#endif
+  int j=0;
+  for (i=0;i<n_left;i++){
+    if (p_remain[i].index){
+      // copy particle
+      p_remain[j]=p_remain[i];
+      p_remain[j].parent_index = p_remain[i].parent_index;
+      p_remain[j].index=1;
+      // set run in initial list
+      particles[p_remain[j].parent_index].index = n_pass;
+#ifdef DEBUG_SPLIT_MERGE
+      cout << p_remain[j].parent_index << " ";
+#endif
+      j++;
+    }
+  }
+#ifdef DEBUG_SPLIT_MERGE
+  cout << endl;
+#endif
+  n_left = j;
+  p_remain.resize(j);
+
+  merge_collinear_and_remove_soft();
+
+  return 0;
+}
+
+
+/*
+ * really do the splitting and merging
+ * At the end, the vector jets is filled with the jets found.
+ * the 'contents' field of each jets contains the indices
+ * of the particles included in that jet. 
+ *  - overlap_tshold    threshold for splitting/merging transition
+ *  - ptmin             minimal pT allowed for jets
+ * return the number of jets is returned
+ ******************************************************************/
+int Csplit_merge::perform(double overlap_tshold, double ptmin){
+  // iterators for the 2 jets
+  cjet_iterator j1;
+  cjet_iterator j2;
+
+  pt_min2 = ptmin*ptmin;
+
+  if (candidates->size()==0)
+    return 0;
+
+  if (overlap_tshold>=1.0 || overlap_tshold <= 0) {
+    ostringstream message;
+    message << "Illegal value for overlap_tshold, f = " << overlap_tshold;
+    message << "  (legal values are 0<f<1)";
+    throw Csiscone_error(message.str());
+  }
+
+  // overlap (the contents of this variable depends on the choice for
+  // the split--merge variable.)
+  // Note that the square of the ovelap is used
+  double overlap2;
+
+  // avoid to compute tshold*tshold at each overlap
+  double overlap_tshold2 = overlap_tshold*overlap_tshold;
+
+  do{
+    if (candidates->size()>0){
+      // browse for the first jet
+      j1 = candidates->begin();
+      
+      // if hardest jet does not pass threshold then nothing else will
+      // either so one stops the split merge.
+      if (j1->sm_var2<SM_var2_hardest_cut_off) {break;}
+
+      // browse for the second jet
+      j2 = j1;
+      j2++;
+      int j2_relindex = 1; // used only in ifdef, but costs little so keep it outside
+
+      while (j2 != candidates->end()){
+#ifdef DEBUG_SPLIT_MERGE
+	show();
+#endif
+	// check overlapping
+	if (get_overlap(*j1, *j2, &overlap2)){
+	  // check if overlapping energy passes threshold
+	  // Note that this depends on the ordering variable
+#ifdef DEBUG_SPLIT_MERGE
+          cout << "overlap between cdt 1 and cdt " << j2_relindex+1 << " with overlap " 
+               << sqrt(overlap2/j2->sm_var2) << endl<<endl;
+#endif
+	  if (overlap2<overlap_tshold2*j2->sm_var2){
+	    // split jets
+	    split(j1, j2);
+	    
+	    // update iterators
+	    j2 = j1 = candidates->begin();
+            j2_relindex = 0;
+	  } else {
+	    // merge jets
+	    merge(j1, j2);
+	    
+	    // update iterators
+	    j2 = j1 = candidates->begin();
+            j2_relindex = 0;
+	  }
+	}
+        // watch out: split/merge might have caused new jets with pt <
+        // ptmin to disappear, so the total number of jets may
+        // have changed by more than expected and j2 might already by
+        // the end of the candidates list...
+        j2_relindex++;
+	if (j2 != candidates->end()) j2++;
+      } // end of loop on the second jet
+      
+      if (j1 != candidates->end()) {
+        // all "second jet" passed without overlapping
+        // (otherwise we won't leave the j2 loop)
+        // => store jet 1 as real jet
+        jets.push_back(*j1);
+        jets[jets.size()-1].v.build_etaphi();
+        // a bug where the contents has non-zero size has been cropping
+        // up in many contexts -- so catch it!
+        assert(j1->contents.size() > 0);
+        jets[jets.size()-1].pass = particles[j1->contents[0]].index;
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+        cand_refs.erase(j1->v.ref);
+#endif
+        candidates->erase(j1);
+
+	//// test that the hardest jet pass the potential cut-off
+	//if ((candidates->size()!=0) && 
+	//    (candidates->begin()->sm_var2<SM_var2_hardest_cut_off)){
+	//  candidates->clear();
+	//}
+      }
+    }
+  } while (candidates->size()>0);
+
+  // sort jets by pT
+  sort(jets.begin(), jets.end(), jets_pt_less);
+#ifdef DEBUG_SPLIT_MERGE
+      show();
+#endif
+
+  return jets.size();
+}
+
+
+
+// save the event on disk
+//  - flux   stream used to save jet contents
+//--------------------------------------------
+int Csplit_merge::save_contents(FILE *flux){
+  jet_iterator it_j;
+  Cjet *j1;
+  int i1, i2;
+
+  fprintf(flux, "# %d jets found\n", (int) jets.size());
+  fprintf(flux, "# columns are: eta, phi, pt and number of particles for each jet\n");
+  for (it_j = jets.begin(), i1=0 ; it_j != jets.end() ; it_j++, i1++){
+    j1 = &(*it_j);
+    j1->v.build_etaphi();
+    fprintf(flux, "%lf\t%lf\t%le\t%d\n", 
+	    j1->v.eta, j1->v.phi, j1->v.perp(), j1->n);
+  }
+  
+  fprintf(flux, "# jet contents\n");
+  fprintf(flux, "# columns are: eta, phi, pt, particle index and jet number\n");
+  for (it_j = jets.begin(), i1=0 ; it_j != jets.end() ; it_j++, i1++){
+    j1 = &(*it_j);
+    for (i2=0;i2<j1->n;i2++)
+      fprintf(flux, "%lf\t%lf\t%le\t%d\t%d\n", 
+      	      particles[j1->contents[i2]].eta, particles[j1->contents[i2]].phi,
+      	      particles[j1->contents[i2]].perp(), j1->contents[i2], i1);
+  }
+  
+  return 0;
+}
+
+
+// show current jets/candidate status
+//------------------------------------
+int Csplit_merge::show(){
+  jet_iterator it_j;
+  cjet_iterator it_c;
+  Cjet *j;
+  const Cjet *c;
+  int i1, i2;
+
+  for (it_j = jets.begin(), i1=0 ; it_j != jets.end() ; it_j++, i1++){
+    j = &(*it_j);
+    fprintf(stdout, "jet %2d: %le\t%le\t%le\t%le\t", i1+1,
+	    j->v.px, j->v.py, j->v.pz, j->v.E);
+    for (i2=0;i2<j->n;i2++)
+      fprintf(stdout, "%d ", j->contents[i2]);
+    fprintf(stdout, "\n");
+  }
+  
+  for (it_c = candidates->begin(), i1=0 ; it_c != candidates->end() ; it_c++, i1++){
+    c = &(*it_c);
+    fprintf(stdout, "cdt %2d: %le\t%le\t%le\t%le\t%le\t", i1+1,
+	    c->v.px, c->v.py, c->v.pz, c->v.E, sqrt(c->sm_var2));
+    for (i2=0;i2<c->n;i2++)
+      fprintf(stdout, "%d ", c->contents[i2]);
+    fprintf(stdout, "\n");
+  }
+  
+  fprintf(stdout, "\n");
+  return 0;
+}
+
+
+// get the overlap between 2 jets
+//  - j1        first jet
+//  - j2        second jet
+//  - overlap2  returned overlap^2 (determined by the choice of SM variable)
+// return true if overlapping, false if disjoint
+//---------------------------------------------------------------------
+bool Csplit_merge::get_overlap(const Cjet &j1, const Cjet &j2, double *overlap2){
+  // check if ranges overlap
+  if (!is_range_overlap(j1.range,j2.range))
+    return false;
+
+  int i1,i2;
+  bool is_overlap;
+
+  // initialise
+  i1=i2=idx_size=0;
+  is_overlap = false;
+  Cmomentum v;
+  double pt_tilde=0.0;
+
+  // compute overlap
+  // at the same time, we store union in indices
+  do{
+    if (j1.contents[i1]<j2.contents[i2]){
+      indices[idx_size] = j1.contents[i1];
+      i1++;
+    } else if (j1.contents[i1]>j2.contents[i2]){
+      indices[idx_size] = j2.contents[i2];
+      i2++;
+    } else { // (j1.contents[i1]==j2.contents[i2])
+      v += particles[j1.contents[i1]];
+      pt_tilde += pt[j1.contents[i1]];
+      indices[idx_size] = j1.contents[i1];
+      i1++;
+      i2++;
+      is_overlap = true;
+    }
+    idx_size++;
+  } while ((i1<j1.n) && (i2<j2.n));
+
+  // finish computing union
+  // (only needed if overlap !)
+  if (is_overlap){
+    while (i1<j1.n){
+      indices[idx_size] = j1.contents[i1];
+      i1++;
+      idx_size++;
+    }
+    while (i2<j2.n){
+      indices[idx_size] = j2.contents[i2];
+      i2++;
+      idx_size++;
+    }
+  }
+
+  // assign the overlapping var as return variable
+  (*overlap2) = get_sm_var2(v, pt_tilde);
+
+  return is_overlap;
+}
+
+
+
+// split the two given jet.
+// during this procedure, the jets j1 & j2 are replaced
+// by 2 new jets. Common particles are associted to the 
+// closest initial jet.
+//  - it_j1  iterator of the first jet in 'candidates'
+//  - it_j2  iterator of the second jet in 'candidates'
+//  - j1     first jet (Cjet instance)
+//  - j2     second jet (Cjet instance)
+// return true on success, false on error
+////////////////////////////////////////////////////////////////
+bool Csplit_merge::split(cjet_iterator &it_j1, cjet_iterator &it_j2){
+  int i1, i2;
+  Cjet jet1, jet2;
+  double eta1, phi1, eta2, phi2;
+  double dx1, dy1, dx2, dy2;
+  Cmomentum tmp;
+  Cmomentum *v;
+
+  // shorthand to avoid having "->" all over the place
+  const Cjet & j1 = * it_j1;
+  const Cjet & j2 = * it_j2;
+
+  i1=i2=0;
+  jet2.v = jet1.v = Cmomentum();
+  jet2.pt_tilde = jet1.pt_tilde = 0.0;
+
+  // compute centroids
+  tmp = j1.v;
+  tmp.build_etaphi();
+  eta1 = tmp.eta;
+  phi1 = tmp.phi;
+
+  tmp = j2.v;
+  tmp.build_etaphi();
+  eta2 = tmp.eta;
+  phi2 = tmp.phi;
+
+  jet1.v = jet2.v = Cmomentum();  
+
+  // compute jet splitting
+  do{
+    if (j1.contents[i1]<j2.contents[i2]){
+      // particle i1 belong only to jet 1
+      v = &(particles[j1.contents[i1]]);
+      jet1.contents.push_back(j1.contents[i1]);
+      jet1.v += *v;
+      jet1.pt_tilde += pt[j1.contents[i1]];
+      i1++;
+      jet1.range.add_particle(v->eta,v->phi);
+    } else if (j1.contents[i1]>j2.contents[i2]){
+      // particle i2 belong only to jet 2
+      v = &(particles[j2.contents[i2]]);
+      jet2.contents.push_back(j2.contents[i2]);
+      jet2.v += *v;
+      jet2.pt_tilde += pt[j2.contents[i2]];
+      i2++;
+      jet2.range.add_particle(v->eta,v->phi);
+    } else { // (j1.contents[i1]==j2.contents[i2])
+      // common particle, decide which is the closest centre
+      v = &(particles[j1.contents[i1]]);
+
+      // distance w.r.t. centroid 1
+      dx1 = eta1 - v->eta;
+      dy1 = fabs(phi1 - v->phi);
+      if (dy1>M_PI) 
+	dy1 -= twopi;
+
+      // distance w.r.t. centroid 2
+      dx2 = eta2 - v->eta;
+      dy2 = fabs(phi2 - v->phi);
+      if (dy2>M_PI) 
+	dy2 -= twopi;
+
+      //? what when == ?
+      double d1sq = dx1*dx1+dy1*dy1;
+      double d2sq = dx2*dx2+dy2*dy2;
+      // do bookkeeping on most ambiguous split
+      if (fabs(d1sq-d2sq) < most_ambiguous_split) 
+        most_ambiguous_split = fabs(d1sq-d2sq);
+
+      if (d1sq<d2sq){
+	// particle i1 belong only to jet 1
+	jet1.contents.push_back(j1.contents[i1]);
+	jet1.v += *v;
+	jet1.pt_tilde += pt[j1.contents[i1]];
+	jet1.range.add_particle(v->eta,v->phi);
+      } else {
+	// particle i2 belong only to jet 2
+	jet2.contents.push_back(j2.contents[i2]);
+	jet2.v += *v;
+	jet2.pt_tilde += pt[j2.contents[i2]];
+	jet2.range.add_particle(v->eta,v->phi);
+      }      
+
+      i1++;
+      i2++;
+    }
+  } while ((i1<j1.n) && (i2<j2.n));
+  
+  while (i1<j1.n){
+    v = &(particles[j1.contents[i1]]);
+    jet1.contents.push_back(j1.contents[i1]);
+    jet1.v += *v;
+    jet1.pt_tilde += pt[j1.contents[i1]];
+    i1++;
+    jet1.range.add_particle(v->eta,v->phi);
+  }
+  while (i2<j2.n){
+    v = &(particles[j2.contents[i2]]);
+    jet2.contents.push_back(j2.contents[i2]);
+    jet2.v += *v;
+    jet2.pt_tilde += pt[j2.contents[i2]];
+    i2++;
+    jet2.range.add_particle(v->eta,v->phi);
+  }
+
+  // finalise jets
+  jet1.n = jet1.contents.size();
+  jet2.n = jet2.contents.size();
+
+  //jet1.range = j1.range;
+  //jet2.range = j2.range;
+
+  // remove previous jets
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+  cand_refs.erase(j1.v.ref);
+  cand_refs.erase(j2.v.ref);
+#endif
+  candidates->erase(it_j1);
+  candidates->erase(it_j2);
+
+  // reinsert new ones
+  insert(jet1);
+  insert(jet2);
+
+  return true;
+}
+
+// merge the two given jet.
+// during this procedure, the jets j1 & j2 are replaced
+// by 1 single jets containing both of them.
+//  - it_j1  iterator of the first jet in 'candidates'
+//  - it_j2  iterator of the second jet in 'candidates'
+// return true on success, false on error
+////////////////////////////////////////////////////////////////
+bool Csplit_merge::merge(cjet_iterator &it_j1, cjet_iterator &it_j2){
+  Cjet jet;
+  int i;
+
+  // build new jet
+  // note: particles within j1 & j2 have already been stored in indices
+  for (i=0;i<idx_size;i++){
+    jet.contents.push_back(indices[i]);
+    jet.v += particles[indices[i]];
+    jet.pt_tilde += pt[indices[i]];
+  }
+  jet.n = jet.contents.size();
+
+  // deal with ranges
+  jet.range = range_union(it_j1->range, it_j2->range);
+
+  // remove old candidates
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+  if (merge_identical_protocones){
+    cand_refs.erase(it_j1->v.ref);
+    cand_refs.erase(it_j2->v.ref);
+  }
+#endif
+  candidates->erase(it_j1);
+  candidates->erase(it_j2);
+
+  // reinsert new candidate
+  insert(jet);
+
+  return true;
+}
+
+/**
+ * Check whether or not a jet has to be inserted in the 
+ * list of protojets. If it has, set its sm_variable and
+ * insert it to the list of protojets.
+ */
+bool Csplit_merge::insert(Cjet &jet){
+
+  // eventually check that no other candidate are present with the
+  // same cone contents. We recall that this automatic merging of
+  // identical protocones can lead to infrared-unsafe situations.
+#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
+  if ((merge_identical_protocones) && (!cand_refs.insert(jet.v.ref).second))
+    return false;
+#endif
+
+  // check that the protojet has large enough pt
+  if (jet.v.perp2()<pt_min2)
+    return false;
+
+  // assign SM variable
+  jet.sm_var2 = get_sm_var2(jet.v, jet.pt_tilde);
+
+  // insert the jet.
+  candidates->insert(jet);
+
+  return true;
+}
+
+/**
+ * given a 4-momentum and its associated pT, return the 
+ * variable that has to be used for SM
+ * \param v          4 momentum of the protojet
+ * \param pt_tilde   pt_tilde of the protojet
+ */
+double Csplit_merge::get_sm_var2(Cmomentum &v, double &pt_tilde){
+  switch(ptcomparison.split_merge_scale) {
+  case SM_pt:      return v.perp2();            
+  case SM_mt:      return v.perpmass2();        
+  case SM_pttilde: return pt_tilde*pt_tilde;
+  case SM_Et:      return v.Et2();
+  default:
+    throw Csiscone_error("Unsupported split-merge scale choice: "
+                                 + ptcomparison.SM_scale_name());
+  }
+
+  return 0.0;
+}
+
+}
Index: /trunk/Utilities/Fastjet/plugins/SISCone/src/vicinity.cc
===================================================================
--- /trunk/Utilities/Fastjet/plugins/SISCone/src/vicinity.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/plugins/SISCone/src/vicinity.cc	(revision 11)
@@ -0,0 +1,295 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: vicinity.cpp                                                        //
+// Description: source file for particle vicinity (Cvicinity class)          //
+// This file is part of the SISCone project.                                 //
+// For more details, see http://projects.hepforge.org/siscone                //
+//                                                                           //
+// Copyright (c) 2006 Gavin Salam and Gregory Soyez                          //
+//                                                                           //
+// This program is free software; you can redistribute it and/or modify      //
+// it under the terms of the GNU General Public License as published by      //
+// the Free Software Foundation; either version 2 of the License, or         //
+// (at your option) any later version.                                       //
+//                                                                           //
+// This program is distributed in the hope that it will be useful,           //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of            //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
+// GNU General Public License for more details.                              //
+//                                                                           //
+// You should have received a copy of the GNU General Public License         //
+// along with this program; if not, write to the Free Software               //
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
+//                                                                           //
+// $Revision: 1.1 $//
+// $Date: 2008-11-06 14:32:13 $//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "../interface/vicinity.h"
+#include <math.h>
+#include <algorithm>
+#include <iostream>
+
+namespace siscone{
+
+using namespace std;
+
+/*************************************************************
+ * Cvicinity_elm implementation                              *
+ * element in the vicinity of a parent.                      *
+ * class used to manage one points in the vicinity           *
+ * of a parent point.                                        *
+ *************************************************************/
+
+// ordering pointers to Cvicinity_elm
+//------------------------------------
+bool ve_less(Cvicinity_elm *ve1, Cvicinity_elm *ve2){
+  return ve1->angle < ve2->angle;
+}
+
+
+/*************************************************************
+ * Cvicinity implementation                                  *
+ * list of element in the vicinity of a parent.              *
+ * class used to manage the points which are in the vicinity *
+ * of a parent point. The construction of the list can be    *
+ * made from a list of points or from a quadtree.            *
+ *************************************************************/
+
+// default constructor
+//---------------------
+Cvicinity::Cvicinity(){
+  n_part = 0;
+
+  ve_list = NULL;
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  quadtree = NULL;
+#endif
+
+  parent = NULL;
+  VR2 = VR = 0.0;
+
+}
+
+// constructor with initialisation
+//---------------------------------
+Cvicinity::Cvicinity(vector<Cmomentum> &_particle_list){
+  parent = NULL;
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  quadtree = NULL;
+#endif
+  VR2 = VR = 0.0;
+
+  set_particle_list(_particle_list);
+}
+
+// default destructor
+//--------------------
+Cvicinity::~Cvicinity(){
+  if (ve_list!=NULL)
+    delete[] ve_list;
+
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  if (quadtree!=NULL)
+    delete quadtree;
+#endif
+}
+
+/*
+ * set the particle_list
+ *  - particle_list   list of particles (type Cmomentum)
+ *  - n               number of particles in the list
+ ************************************************************/ 
+void Cvicinity::set_particle_list(vector<Cmomentum> &_particle_list){
+  int i,j;
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  double eta_max=0.0;
+#endif
+  
+  // if the particle list is not empty, destroy it !
+  if (ve_list!=NULL){
+    delete[] ve_list;
+  }
+  vicinity.clear();
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  if (quadtree!=NULL)
+    delete quadtree;
+#endif
+
+  // allocate memory array for particles
+  // Note: - we compute max for |eta|
+  //       - we allocate indices to particles
+  n_part = 0;
+  plist.clear();
+  pincluded.clear();
+  for (i=0;i<(int) _particle_list.size();i++){
+    // if a particle is colinear with the beam (infinite rapidity)
+    // we do not take it into account
+    if (fabs(_particle_list[i].pz)!=_particle_list[i].E){
+      plist.push_back(_particle_list[i]);
+      pincluded.push_back(Cvicinity_inclusion()); // zero inclusion status
+
+      // the parent_index is handled in the split_merge because 
+      // of our multiple-pass procedure.
+      // Hence, it is not required here any longer.
+      // plist[n_part].parent_index = i;
+      plist[n_part].index = n_part;
+
+      // make sure the reference is randomly created
+      plist[n_part].ref.randomize();
+
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+      if (fabs(plist[n_part].eta)>eta_max) eta_max=fabs(plist[n_part].eta);
+#endif
+
+      n_part++;
+    }
+  }
+
+  // allocate quadtree and vicinity_elm list
+  // note: we set phi in [-pi:pi] as it is the natural range for atan2!
+  ve_list = new Cvicinity_elm[2*n_part];
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+  eta_max+=0.1;
+  quadtree = new Cquadtree(0.0, 0.0, eta_max, M_PI);
+#endif
+
+  // append particle to the vicinity_elm list
+  j = 0;
+  for (i=0;i<n_part;i++){
+#ifdef USE_QUADTREE_FOR_STABILITY_TEST
+    quadtree->add(&plist[i]);
+#endif
+    ve_list[j].v = ve_list[j+1].v = &plist[i];
+    ve_list[j].is_inside = ve_list[j+1].is_inside = &(pincluded[i]);
+    j+=2;
+  }
+
+}
+
+
+/*
+ * build the vicinity list from a list of points.
+ *  - _parent   reference particle
+ *  - _VR       vicinity radius
+ ************************************************************/
+void Cvicinity::build(Cmomentum *_parent, double _VR){
+  int i;
+
+  // set parent and radius
+  parent = _parent;
+  VR  = _VR;
+  VR2 = VR*VR;
+  R2  = 0.25*VR2;
+  R   = 0.5*VR;
+  inv_R_EPS_COCIRC  = 1.0 / R / EPSILON_COCIRCULAR;
+  inv_R_2EPS_COCIRC = 0.5 / R / EPSILON_COCIRCULAR;
+
+  // clear vicinity
+  vicinity.clear();
+
+  // init parent variables
+  pcx = parent->eta;
+  pcy = parent->phi;
+
+  // really browse the particle list
+  for (i=0;i<n_part;i++){
+    append_to_vicinity(&plist[i]);
+  }
+
+  // sort the vicinity
+  sort(vicinity.begin(), vicinity.end(), ve_less);
+
+  vicinity_size = vicinity.size();
+}
+
+
+/// strictly increasing function of the angle 
+inline double sort_angle(double s, double c){
+  if (s==0) return (c>0) ? 0.0 : 2.0;
+  double t=c/s;
+  return (s>0) ? 1-t/(1+fabs(t)) : 3-t/(1+fabs(t));
+}
+
+
+/*
+ * append a particle to the 'vicinity' list after
+ * having computed the angular-ordering quantities
+ *  - v   vector to test
+ **********************************************************/
+void Cvicinity::append_to_vicinity(Cmomentum *v){
+  double dx, dy, d2;
+
+  // skip the particle itself)
+  if (v==parent)
+    return;
+
+  int i=2*(v->index);
+
+  // compute the distance of the i-th particle with the parent
+  dx = v->eta - pcx;
+  dy = v->phi - pcy;
+    
+  // pay attention to the periodicity in phi !
+  if (dy>M_PI) 
+    dy -= twopi;
+  else if (dy<-M_PI) 
+    dy += twopi;
+
+  d2 = dx*dx+dy*dy;
+    
+  // really check if the distance is less than VR
+  if (d2<VR2){
+    double s,c,tmp;
+    
+    // compute the angles used for future ordering ...
+    //  - build temporary variables used for the computation
+    //d   = sqrt(d2);
+    tmp = sqrt(VR2/d2-1);
+
+    // first angle (+)
+    c = 0.5*(dx-dy*tmp);  // cosine of (parent,child) pair w.r.t. horizontal
+    s = 0.5*(dy+dx*tmp);  // sine   of (parent,child) pair w.r.t. horizontal
+    ve_list[i].angle = sort_angle(s,c);
+    ve_list[i].eta = pcx+c;
+    ve_list[i].phi = phi_in_range(pcy+s);
+    ve_list[i].side = true;
+    ve_list[i].cocircular.clear();
+    vicinity.push_back(&(ve_list[i]));
+
+    // second angle (-)    
+    c = 0.5*(dx+dy*tmp);  // cosine of (parent,child) pair w.r.t. horizontal
+    s = 0.5*(dy-dx*tmp);  // sine   of (parent,child) pair w.r.t. horizontal
+    ve_list[i+1].angle = sort_angle(s,c);
+    ve_list[i+1].eta = pcx+c;
+    ve_list[i+1].phi = phi_in_range(pcy+s);
+    ve_list[i+1].side = false;
+    ve_list[i+1].cocircular.clear();
+    vicinity.push_back(&(ve_list[i+1]));
+
+    // now work out the cocircularity range for the two points (range
+    // of angle within which the points stay within a distance
+    // EPSILON_COCIRCULAR of circule
+    // P = parent; C = child; O = Origin (center of circle)
+    Ctwovect OP(pcx - ve_list[i+1].eta, phi_in_range(pcy-ve_list[i+1].phi));
+    Ctwovect OC(v->eta - ve_list[i+1].eta, 
+                phi_in_range(v->phi-ve_list[i+1].phi));
+
+    // two sources of error are (GPS CCN29-19) epsilon/(R sin theta)
+    // and sqrt(2*epsilon/(R (1-cos theta))) and the way things work
+    // out, it is the _smaller_ of the two that is relevant [NB have
+    // changed definition of theta here relative to that used in
+    // CCN29] [NB2: write things so as to avoid zero denominators and
+    // to minimize the multiplications, divisions and above all sqrts
+    // -- that means that c & s are defined including a factor of VR2]
+    c = dot_product(OP,OC);
+    s = fabs(cross_product(OP,OC));
+    double inv_err1 = s * inv_R_EPS_COCIRC;
+    double inv_err2_sq = (R2-c) * inv_R_2EPS_COCIRC;
+    ve_list[i].cocircular_range = pow2(inv_err1) > inv_err2_sq ? 
+                                                     1.0/inv_err1 : 
+                                                     sqrt(1.0/inv_err2_sq);
+    ve_list[i+1].cocircular_range = ve_list[i].cocircular_range;
+  }
+}
+
+}
Index: /trunk/Utilities/Fastjet/src/AreaDefinition.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/AreaDefinition.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/AreaDefinition.cc	(revision 11)
@@ -0,0 +1,79 @@
+//STARTHEADER
+// $Id: AreaDefinition.cc,v 1.1 2008-11-06 14:32:13 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/AreaDefinition.hh"
+#include<sstream>
+#include<string>
+
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+string VoronoiAreaSpec::description() const {
+  ostringstream ostr;
+  ostr << "Voronoi area with effective_Rfact = " << effective_Rfact() ;
+  return ostr.str();
+}
+
+
+//----------------------------------------------------------------------
+///  return info about the type of area being used by this defn
+string AreaDefinition::description() const {
+  ostringstream ostr;
+
+  switch(area_type()) {
+  case active_area:
+    ostr << "Active area (hidden ghosts) with " ;
+    ostr << ghost_spec().description();
+    break;
+  case active_area_explicit_ghosts:
+    ostr << "Active area (explicit ghosts) with " ;
+    ostr << ghost_spec().description();
+    break;
+  case one_ghost_passive_area:
+    ostr << "Passive area (one ghost at a time) with " ;
+    ostr << ghost_spec().description();
+    break;
+  case passive_area:
+    ostr << "Passive area (optimal alg. based on jet.def.), where relevant with " ;
+    ostr << ghost_spec().description()  ;
+    break;
+  case voronoi_area:
+    ostr << voronoi_spec().description();
+    break;
+  default:
+    cerr << "Error: unrecognized area_type in AreaDefinition::description():" 
+         << area_type() << endl;
+    exit(-1);
+  }
+  return ostr.str();
+}
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
Index: /trunk/Utilities/Fastjet/src/BasicRandom.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/BasicRandom.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/BasicRandom.cc	(revision 11)
@@ -0,0 +1,53 @@
+// simple random number generator class taken from nlojet++.
+// $Id: BasicRandom.cc,v 1.1 2008-11-06 14:32:13 ovyn Exp $
+
+//  Copyright (C) 2002 Zoltan Nagy
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+//   nlo includes
+#include "../include/fastjet/internal/BasicRandom.hh"
+
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+//
+//                   random number generator
+//  uses method of L'Ecuyer, (via F.James, comp. phys. comm. 60(1990)329)
+//
+int __default_random_generator(int *__iseed) 
+{
+  int __k = __iseed[0]/53668;
+  __iseed[0] = (__iseed[0] - __k*53668)*40014 - __k*12211;
+  if(__iseed[0] < 0) __iseed[0] += 2147483563;
+  
+  __k = __iseed[1]/52774;
+  __iseed[1] = (__iseed[1] - __k*52774)*40692 - __k*3791;
+  if(__iseed[1] < 0) __iseed[1] += 2147483399;
+  
+  int __iz = __iseed[0] - __iseed[1];
+  if(__iz < 1) __iz += 2147483562;
+  
+  return __iz;
+}
+
+//   global defined random number generator
+BasicRandom<int>     _G_random_int;
+BasicRandom<double>  _G_random_double;
+
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClosestPair2D.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClosestPair2D.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClosestPair2D.cc	(revision 11)
@@ -0,0 +1,496 @@
+//STARTHEADER
+// $Id: ClosestPair2D.cc,v 1.1 2008-11-06 14:32:13 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/internal/ClosestPair2D.hh"
+
+#include<limits>
+#include<iostream>
+#include<iomanip>
+#include<algorithm>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+const unsigned int huge_unsigned = 4294967295U;
+const unsigned int twopow31      = 2147483648U;
+
+using namespace std;
+
+//----------------------------------------------------------------------
+/// takes a point and sets a shuffle with the given shift...
+void ClosestPair2D::_point2shuffle(Point & point, Shuffle & shuffle, 
+				  unsigned int shift) {
+  
+  Coord2D renorm_point = (point.coord - _left_corner)/_range;
+  // make sure the point is sensible
+  //cerr << point.coord.x <<" "<<point.coord.y<<endl;
+  assert(renorm_point.x >=0);
+  assert(renorm_point.x <=1);
+  assert(renorm_point.y >=0);
+  assert(renorm_point.y <=1);
+  
+  shuffle.x = static_cast<unsigned int>(twopow31 * renorm_point.x) + shift;
+  shuffle.y = static_cast<unsigned int>(twopow31 * renorm_point.y) + shift;
+  shuffle.point = &point;
+}
+
+//----------------------------------------------------------------------
+/// compares this shuffle with the other one
+bool ClosestPair2D::Shuffle::operator<(const Shuffle & q) const {
+
+  if (floor_ln2_less(x ^ q.x, y ^ q.y)) {
+    // i = 2 in Chan's algorithm
+    return (y < q.y);
+  } else {
+    // i = 1 in Chan's algorithm
+    return (x < q.x);
+  }
+}
+
+
+
+//----------------------------------------------------------------------
+void ClosestPair2D::_initialize(const std::vector<Coord2D> & positions, 
+			     const Coord2D & left_corner, 
+			     const Coord2D & right_corner,
+			     unsigned int max_size) {
+
+  unsigned int n_positions = positions.size();
+  assert(max_size >= n_positions);
+
+  //_points(positions.size())
+
+  // allow the points array to grow to the following size
+  _points.resize(max_size);
+  // currently unused points are immediately made available on the
+  // stack
+  for (unsigned int i = n_positions; i < max_size; i++) {
+    _available_points.push(&(_points[i]));
+  }
+
+  _left_corner = left_corner;
+  _range       = max((right_corner.x - left_corner.x),
+		     (right_corner.y - left_corner.y));
+
+  // initialise the coordinates for the points and create the zero-shifted
+  // shuffle array
+  vector<Shuffle> shuffles(n_positions);
+  for (unsigned int i = 0; i < n_positions; i++) {
+    // set up the points
+    _points[i].coord = positions[i];
+    _points[i].neighbour_dist2 = numeric_limits<double>::max();
+    _points[i].review_flag = 0;
+
+    // create shuffle with 0 shift.
+    _point2shuffle(_points[i], shuffles[i], 0);
+  }
+
+  // establish what our shifts will be
+  for (unsigned ishift = 0; ishift < _nshift; ishift++) {
+    // make sure we use double-precision for calculating the shifts
+    // since otherwise we will hit integer overflow.
+   _shifts[ishift] = static_cast<unsigned int>(((twopow31*1.0)*ishift)/_nshift);
+    if (ishift == 0) {_rel_shifts[ishift] = 0;}
+    else {_rel_shifts[ishift] = _shifts[ishift] - _shifts[ishift-1];}
+  }
+  //_shifts[0] = 0;
+  //_shifts[1] = static_cast<unsigned int>((twopow31*1.0)/3.0);
+  //_shifts[2] = static_cast<unsigned int>((twopow31*2.0)/3.0);
+  //_rel_shifts[0] = 0;
+  //_rel_shifts[1] = _shifts[1];
+  //_rel_shifts[2] = _shifts[2]-_shifts[1];
+
+  // and how we will search...
+  //_cp_search_range = 49;
+  _cp_search_range = 30;
+  _points_under_review.reserve(_nshift * _cp_search_range);
+
+  // now initialise the three trees
+  for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
+
+    // shift the shuffles if need be.
+    if (ishift > 0) {
+      unsigned rel_shift = _rel_shifts[ishift];
+      for (unsigned int i = 0; i < shuffles.size(); i++) {
+	shuffles[i] += rel_shift; }
+    }
+
+    // sort the shuffles
+    sort(shuffles.begin(), shuffles.end());
+
+    // and create the search tree
+    _trees[ishift] = auto_ptr<Tree>(new Tree(shuffles, max_size));
+
+    // now we look for the closest-pair candidates on this tree
+    circulator circ = _trees[ishift]->somewhere(), start=circ;
+    // the actual range in which we search 
+    unsigned int CP_range = min(_cp_search_range, n_positions-1);
+    do {
+      Point * this_point = circ->point;
+      //cout << _ID(this_point) << " ";
+      this_point->circ[ishift] = circ;
+      // run over all points within _cp_search_range of this_point on tree
+      circulator other = circ;
+      for (unsigned i=0; i < CP_range; i++) {
+	++other;
+	double dist2 = this_point->distance2(*other->point);
+	if (dist2 < this_point->neighbour_dist2) {
+	  this_point->neighbour_dist2 = dist2;
+	  this_point->neighbour       = other->point;
+	}
+      }
+    } while (++circ != start);
+    //cout << endl<<endl;
+  }
+
+  // now initialise the heap object...
+  vector<double> mindists2(n_positions);
+  for (unsigned int i = 0; i < n_positions; i++) {
+    mindists2[i] = _points[i].neighbour_dist2;}
+  
+  _heap = auto_ptr<MinHeap>(new MinHeap(mindists2, max_size));
+}
+
+
+//----------------------------------------------------------------------=
+void ClosestPair2D::closest_pair(unsigned int & ID1, unsigned int & ID2, 
+				 double & distance2) const {
+  ID1 = _heap->minloc();
+  ID2 = _ID(_points[ID1].neighbour);
+  distance2 = _points[ID1].neighbour_dist2;
+  if (ID1 > ID2) swap(ID1,ID2);
+}
+
+
+//----------------------------------------------------------------------
+inline void ClosestPair2D::_add_label(Point * point, unsigned int review_flag) {
+
+  // if it's not already under review, then put it on the list of
+  // points needing review
+  if (point->review_flag == 0) _points_under_review.push_back(point);
+
+  // OR the point's current flag with the requested review flag
+  point->review_flag |= review_flag;
+}
+
+//----------------------------------------------------------------------
+inline void ClosestPair2D::_set_label(Point * point, unsigned int review_flag) {
+
+  // if it's not already under review, then put it on the list of
+  // points needing review
+  if (point->review_flag == 0) _points_under_review.push_back(point);
+
+  // SET the point's current flag to the requested review flag
+  point->review_flag = review_flag;
+}
+
+//----------------------------------------------------------------------
+void ClosestPair2D::remove(unsigned int ID) {
+
+  //cout << "While removing " << ID <<endl;
+
+  Point * point_to_remove = & (_points[ID]);
+
+  // remove this point from the search tree
+  _remove_from_search_tree(point_to_remove);
+
+  // the above statement labels certain points as needing "review" --
+  // deal with them...
+  _deal_with_points_to_review();
+}
+
+
+//----------------------------------------------------------------------
+void ClosestPair2D::_remove_from_search_tree(Point * point_to_remove) {
+
+  // add this point to the list of "available" points (this is
+  // relevant also from the point of view of determining the range
+  // over which we circulate).
+  _available_points.push(point_to_remove);
+
+  // label it so that it goes from the heap
+  _set_label(point_to_remove, _remove_heap_entry);
+
+  // establish the range over which we search (a) for points that have
+  // acquired a new neighbour and (b) for points which had ID as their
+  // neighbour;
+  
+  unsigned int CP_range = min(_cp_search_range, size()-1);
+
+  // then, for each shift
+  for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
+    //cout << "   ishift = " << ishift <<endl;
+    // get the circulator for the point we'll remove and its successor
+    circulator removed_circ = point_to_remove->circ[ishift];
+    circulator right_end = removed_circ.next();
+    // remove the point
+    _trees[ishift]->remove(removed_circ);
+    
+    // next find the point CP_range points to the left
+    circulator left_end  = right_end, orig_right_end = right_end;
+    for (unsigned int i = 0; i < CP_range; i++) {left_end--;}
+
+    if (size()-1 < _cp_search_range) {
+      // we have a smaller range now than before -- but when seeing who 
+      // could have had ID as a neighbour, we still need to use the old
+      // range for seeing how far back we search (but new separation between
+      // points). [cf CCN28-42]
+      left_end--; right_end--;
+    }
+
+    // and then for each left-end point: establish if the removed
+    // point was its neighbour [in which case a new neighbour must be
+    // found], otherwise see if the right-end point is a closer neighbour
+    do {
+      Point * left_point = left_end->point;
+
+      //cout << "    visited " << setw(3)<<_ID(left_point)<<" (its neighbour was "<<	setw(3)<< _ID(left_point->neighbour)<<")"<<endl;
+
+      if (left_point->neighbour == point_to_remove) {
+	// we'll deal with it later...
+	_add_label(left_point, _review_neighbour);
+      } else {
+	// check to see if right point has become its closest neighbour
+	double dist2 = left_point->distance2(*right_end->point);
+	if (dist2 < left_point->neighbour_dist2) {
+	  left_point->neighbour = right_end->point;
+	  left_point->neighbour_dist2 = dist2;
+	  // NB: (LESSER) REVIEW NEEDED HERE TOO...
+	  _add_label(left_point, _review_heap_entry);
+	}
+      }
+      ++right_end;
+    } while (++left_end != orig_right_end);
+  } // ishift...
+
+}
+
+
+//----------------------------------------------------------------------
+void ClosestPair2D::_deal_with_points_to_review() {
+
+  // the range in which we carry out searches for new neighbours on
+  // the search tree
+  unsigned int CP_range = min(_cp_search_range, size()-1);
+
+  // now deal with the points that are "under review" in some way
+  // (have lost their neighbour, or need their heap entry updating)
+  while(_points_under_review.size() > 0) {
+    // get the point to be considered
+    Point * this_point = _points_under_review.back();
+    // remove it from the list
+    _points_under_review.pop_back();  
+    
+    if (this_point->review_flag & _remove_heap_entry) {
+      // make sure no other flags are on (it wouldn't be consistent?)
+      assert(!(this_point->review_flag ^ _remove_heap_entry));
+      _heap->remove(_ID(this_point));
+    } 
+    // check to see if the _review_neighbour flag is on
+    else {
+      if (this_point->review_flag & _review_neighbour) {
+	this_point->neighbour_dist2 = numeric_limits<double>::max();
+	// among all three shifts
+	for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
+	  circulator other = this_point->circ[ishift];
+	  // among points within CP_range
+	  for (unsigned i=0; i < CP_range; i++) {
+	    ++other;
+	    double dist2 = this_point->distance2(*other->point);
+	    if (dist2 < this_point->neighbour_dist2) {
+	      this_point->neighbour_dist2 = dist2;
+	      this_point->neighbour       = other->point;
+	    }
+	  }
+	}
+      }
+
+      // for any non-zero review flag we'll have to update the heap
+      _heap->update(_ID(this_point), this_point->neighbour_dist2);
+    }
+
+    // "delabel" the point
+    this_point->review_flag = 0; 
+
+  }
+
+}
+
+//----------------------------------------------------------------------
+unsigned int ClosestPair2D::insert(const Coord2D & new_coord) {
+
+  // get hold of a point
+  assert(_available_points.size() > 0);
+  Point * new_point = _available_points.top();
+  _available_points.pop();
+
+  // set the point's coordinate
+  new_point->coord = new_coord;
+  
+  // now find it's neighbour in the search tree
+  _insert_into_search_tree(new_point);
+
+  // sort out other points that may have been affected by this, 
+  // and/or for which the heap needs to be updated
+  _deal_with_points_to_review();
+
+  // 
+  return _ID(new_point);
+}
+
+//----------------------------------------------------------------------
+unsigned int ClosestPair2D::replace(unsigned int ID1, unsigned int ID2, 
+				    const Coord2D & position) {
+  
+  // deletion from tree...
+  Point * point_to_remove = & (_points[ID1]);
+  _remove_from_search_tree(point_to_remove);
+
+  point_to_remove = & (_points[ID2]);
+  _remove_from_search_tree(point_to_remove);
+
+  // insertion into tree
+  // get hold of a point
+  Point * new_point = _available_points.top();
+  _available_points.pop();
+
+  // set the point's coordinate
+  new_point->coord = position;
+  
+  // now find it's neighbour in the search tree
+  _insert_into_search_tree(new_point);
+
+  // the above statement labels certain points as needing "review" --
+  // deal with them...
+  _deal_with_points_to_review();
+
+  //
+  return _ID(new_point);
+
+}
+
+
+//----------------------------------------------------------------------
+void ClosestPair2D::replace_many(
+                  const std::vector<unsigned int> & IDs_to_remove,
+		  const std::vector<Coord2D> & new_positions,
+		  std::vector<unsigned int> & new_IDs) {
+
+  // deletion from tree...
+  for (unsigned int i = 0; i < IDs_to_remove.size(); i++) {
+    _remove_from_search_tree(& (_points[IDs_to_remove[i]]));
+  }
+
+  // insertion into tree
+  new_IDs.resize(0);
+  for (unsigned int i = 0; i < new_positions.size(); i++) {
+    Point * new_point = _available_points.top();
+    _available_points.pop();
+    // set the point's coordinate
+    new_point->coord = new_positions[i];
+    // now find it's neighbour in the search tree
+    _insert_into_search_tree(new_point);
+    // record the ID
+    new_IDs.push_back(_ID(new_point));
+  }
+
+  // the above statement labels certain points as needing "review" --
+  // deal with them...
+  _deal_with_points_to_review();
+
+}
+
+
+//----------------------------------------------------------------------
+void ClosestPair2D::_insert_into_search_tree(Point * new_point) {
+
+  // this point will have to have it's heap entry reviewed...
+  _set_label(new_point, _review_heap_entry);
+
+  // set the current distance to "infinity"
+  new_point->neighbour_dist2 = numeric_limits<double>::max();
+  
+  // establish how far we will be searching;
+  unsigned int CP_range = min(_cp_search_range, size()-1);
+
+  for (unsigned ishift = 0; ishift < _nshift; ishift++) {
+    // create the shuffle
+    Shuffle new_shuffle;
+    _point2shuffle(*new_point, new_shuffle, _shifts[ishift]);
+    
+    // insert it into the tree
+    circulator new_circ = _trees[ishift]->insert(new_shuffle);
+    new_point->circ[ishift] = new_circ;
+
+    // now get hold of the right and left edges of the region we will be
+    // looking at (cf CCN28-43)
+    circulator right_edge = new_circ; right_edge++;
+    circulator left_edge  = new_circ;
+    for (unsigned int i = 0; i < CP_range; i++) {left_edge--;}
+
+    // now 
+    do {
+      Point * left_point  = left_edge->point;
+      Point * right_point = right_edge->point;
+
+      // see if the new point is closer to the left-edge than the latter's
+      // current neighbour
+      double new_dist2 = left_point->distance2(*new_point);
+      if (new_dist2 < left_point->neighbour_dist2) {
+	left_point->neighbour_dist2 = new_dist2;
+	left_point->neighbour       = new_point;
+	_add_label(left_point, _review_heap_entry);
+      }
+
+      // see if the right-point is closer to the new point than it's current
+      // neighbour
+      new_dist2 = new_point->distance2(*right_point);
+      if (new_dist2 < new_point->neighbour_dist2) {
+	new_point->neighbour_dist2 = new_dist2;
+	new_point->neighbour = right_point;
+      }
+
+      // if the right-edge point was the left-edge's neighbour, then
+      // then it's just gone off-radar and the left-point will need to
+      // have its neighbour recalculated [actually, this is overdoing
+      // it a little, since right point may be an less "distant"
+      // (circulator distance) in one of the other shifts -- but not
+      // sure how to deal with this...]
+      if (left_point->neighbour == right_point) {
+	_add_label(left_point, _review_neighbour);
+      }
+
+      // shift the left and right edges until left edge hits new_circ
+      right_edge++;
+    } while (++left_edge != new_circ);
+  }
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequence.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence.cc	(revision 11)
@@ -0,0 +1,904 @@
+//STARTHEADER
+// $Id: ClusterSequence.cc,v 1.1 2008-11-06 14:32:13 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/Error.hh"
+#include "../include/fastjet/PseudoJet.hh"
+#include "../include/fastjet/ClusterSequence.hh"
+#include "../include/fastjet/version.hh" // stores the current version number
+#include<iostream>
+#include<sstream>
+#include<cmath>
+#include<cstdlib>
+#include<cassert>
+#include<string>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+//// initialised static member has to go in the .cc code
+JetAlgorithm ClusterSequence::_default_jet_algorithm = kt_algorithm;
+//
+
+
+//----------------------------------------------------------------------
+void ClusterSequence::_initialise_and_run (
+				  const double & R,
+				  const Strategy & strategy,
+				  const bool & writeout_combinations) {
+
+  JetDefinition jet_def(_default_jet_algorithm, R, strategy);
+  _initialise_and_run(jet_def, writeout_combinations);
+}
+
+
+//----------------------------------------------------------------------
+void ClusterSequence::_initialise_and_run (
+				  const JetDefinition & jet_def,
+				  const bool & writeout_combinations) {
+
+  // transfer all relevant info into internal variables
+  _decant_options(jet_def, writeout_combinations);
+
+  // set up the history entries for the initial particles (those
+  // currently in _jets)
+  _fill_initial_history();
+
+  // run the plugin if that's what's decreed
+  if (_jet_algorithm == plugin_algorithm) {
+    _plugin_activated = true;
+    _jet_def.plugin()->run_clustering( (*this) );
+    _plugin_activated = false;
+    return;
+  }
+
+
+  // automatically redefine the strategy according to N if that is
+  // what the user requested -- transition points (and especially
+  // their R-dependence) are based on empirical observations for a
+  // R=0.4, 0.7 and 1.0, running on toth (3.4GHz, Pentium IV D [dual
+  // core] with 2MB of cache).
+  if (_strategy == Best) {
+    int N = _jets.size();
+    if (N > 6200/pow(_Rparam,2.0) 
+	&& jet_def.jet_algorithm() == cambridge_algorithm) {
+      _strategy = NlnNCam;}
+    else
+#ifndef DROP_CGAL
+    if (N > 16000/pow(_Rparam,1.15)) {
+      _strategy = NlnN; }   
+    else                    
+#endif  // DROP_CGAL
+      if (N > 450) {
+      _strategy = N2MinHeapTiled;
+    }
+    else if (N > 55*max(0.5,min(1.0,_Rparam))) {// empirical scaling with R
+      _strategy = N2Tiled;
+    } else {
+      _strategy = N2Plain;
+    }
+  }
+
+
+  // run the code containing the selected strategy
+  if (_strategy == NlnN || _strategy == NlnN3pi 
+      || _strategy == NlnN4pi ) {
+    this->_delaunay_cluster();
+  } else if (_strategy ==  N3Dumb ) {
+    this->_really_dumb_cluster();
+  } else if (_strategy == N2Tiled) {
+    this->_faster_tiled_N2_cluster();
+  } else if (_strategy == N2PoorTiled) {
+    this->_tiled_N2_cluster();
+  } else if (_strategy == N2Plain) {
+    this->_simple_N2_cluster();
+  } else if (_strategy == N2MinHeapTiled) {
+    this->_minheap_faster_tiled_N2_cluster();
+  } else if (_strategy == NlnNCam4pi) {
+    this->_CP2DChan_cluster();
+  } else if (_strategy == NlnNCam2pi2R) {
+    this->_CP2DChan_cluster_2pi2R();
+  } else if (_strategy == NlnNCam) {
+    this->_CP2DChan_cluster_2piMultD();
+  } else {
+    ostringstream err;
+    err << "Unrecognised value for strategy: "<<_strategy;
+    throw Error(err.str());
+    //assert(false);
+  }
+}
+
+
+// these needs to be defined outside the class definition.
+bool ClusterSequence::_first_time = true;
+int ClusterSequence::_n_exclusive_warnings = 0;
+
+
+//----------------------------------------------------------------------
+// the version string
+string fastjet_version_string() {
+  return "FastJet version "+string(fastjet_version);
+}
+
+
+//----------------------------------------------------------------------
+// prints a banner on the first call
+void ClusterSequence::_print_banner() {
+
+  if (!_first_time) {return;}
+  _first_time = false;
+  
+  
+  //Symp. Discr. Alg, p.472 (2002) and  CGAL (http://www.cgal.org);
+
+  cout << "#--------------------------------------------------------------------------\n";
+  cout << "#                      FastJet release " << fastjet_version << endl;
+  cout << "#            Written by M. Cacciari, G.P. Salam and G. Soyez            \n"; 
+  cout << "#              http://www.lpthe.jussieu.fr/~salam/fastjet		   \n"; 
+  cout << "#								      	   \n";
+  cout << "# Longitudinally invariant Kt, anti-Kt, and inclusive Cambridge/Aachen  \n";
+  cout << "# clustering using fast geometric algorithms, with area measures and optional\n";
+  cout << "# external jet-finder plugins.                                          \n";
+  cout << "# Please cite Phys. Lett. B641 (2006) [hep-ph/0512210] if you use this code.\n";
+  cout << "#								      	   \n";
+  cout << "# This package uses T.Chan's closest pair algorithm, Proc.13th ACM-SIAM \n";
+  cout << "# Symp. Discr. Alg, p.472 (2002), S.Fortune's Voronoi algorithm and code " ;
+#ifndef DROP_CGAL
+  cout << endl << "# and CGAL: http://www.cgal.org/";
+#endif  // DROP_CGAL
+  cout << ".\n";
+  cout << "#-------------------------------------------------------------------------\n";
+}
+
+//----------------------------------------------------------------------
+// transfer all relevant info into internal variables
+void ClusterSequence::_decant_options(const JetDefinition & jet_def,
+                                      const bool & writeout_combinations) {
+
+  // let the user know what's going on
+  _print_banner();
+
+  // make a local copy of the jet definition (for future use?)
+  _jet_def = jet_def;
+  
+  _writeout_combinations = writeout_combinations;
+  _jet_algorithm = jet_def.jet_algorithm();
+  _Rparam = jet_def.R();  _R2 = _Rparam*_Rparam; _invR2 = 1.0/_R2;
+  _strategy = jet_def.strategy();
+
+  // disallow interference from the plugin
+  _plugin_activated = false;
+  
+}
+
+
+//----------------------------------------------------------------------
+// initialise the history in a standard way
+void ClusterSequence::_fill_initial_history () {
+
+  if (_jets.size() == 0) {throw Error("Cannot run jet-finder on empty event");}
+
+  // reserve sufficient space for everything
+  _jets.reserve(_jets.size()*2);
+  _history.reserve(_jets.size()*2);
+
+  for (int i = 0; i < static_cast<int>(_jets.size()) ; i++) {
+    history_element element;
+    element.parent1 = InexistentParent;
+    element.parent2 = InexistentParent;
+    element.child   = Invalid;
+    element.jetp_index = i;
+    element.dij     = 0.0;
+    element.max_dij_so_far = 0.0;
+
+    _history.push_back(element);
+    
+    // do any momentum preprocessing needed by the recombination scheme
+    _jet_def.recombiner()->preprocess(_jets[i]);
+
+    // get cross-referencing right from PseudoJets
+    _jets[i].set_cluster_hist_index(i);
+  }
+  _initial_n = _jets.size();
+}
+
+
+//----------------------------------------------------------------------
+// Return the component corresponding to the specified index.
+// taken from CLHEP
+string ClusterSequence::strategy_string ()  const {
+  string strategy;
+  switch(_strategy) {
+  case NlnN:
+    strategy = "NlnN"; break;
+  case NlnN3pi:
+    strategy = "NlnN3pi"; break;
+  case NlnN4pi:
+    strategy = "NlnN4pi"; break;
+  case N2Plain:
+    strategy = "N2Plain"; break;
+  case N2Tiled:
+    strategy = "N2Tiled"; break;
+  case N2MinHeapTiled:
+    strategy = "N2MinHeapTiled"; break;
+  case N2PoorTiled:
+    strategy = "N2PoorTiled"; break;
+  case N3Dumb:
+    strategy = "N3Dumb"; break;
+  case NlnNCam4pi:
+    strategy = "NlnNCam4pi"; break;
+  case NlnNCam2pi2R:
+    strategy = "NlnNCam2pi2R"; break;
+  case NlnNCam:
+    strategy = "NlnNCam"; break; // 2piMultD
+  case plugin_strategy:
+    strategy = "plugin strategy"; break;
+  default:
+    strategy = "Unrecognized";
+  }
+  return strategy;
+}  
+
+
+double ClusterSequence::jet_scale_for_algorithm(
+				  const PseudoJet & jet) const {
+  if (_jet_algorithm == kt_algorithm)             {return jet.kt2();}
+  else if (_jet_algorithm == cambridge_algorithm) {return 1.0;}
+  else if (_jet_algorithm == antikt_algorithm) {
+    double kt2=jet.kt2();
+    return kt2 > 1e-300 ? 1.0/kt2 : 1e300;
+  } else if (_jet_algorithm == cambridge_for_passive_algorithm) {
+    double kt2 = jet.kt2();
+    double lim = _jet_def.extra_param();
+    if (kt2 < lim*lim && kt2 != 0.0) {
+      return 1.0/kt2;
+    } else {return 1.0;}
+  } else {throw Error("Unrecognised jet finder");}
+}
+
+
+//----------------------------------------------------------------------
+/// transfer the sequence contained in other_seq into our own;
+/// any plugin "extras" contained in the from_seq will be lost
+/// from there.
+void ClusterSequence::transfer_from_sequence(ClusterSequence & from_seq) {
+
+  // the metadata
+  _jet_def                 = from_seq._jet_def                ;
+  _writeout_combinations   = from_seq._writeout_combinations  ;
+  _initial_n               = from_seq._initial_n              ;
+  _Rparam                  = from_seq._Rparam                 ;
+  _R2                      = from_seq._R2                     ;
+  _invR2                   = from_seq._invR2                  ;
+  _strategy                = from_seq._strategy               ;
+  _jet_algorithm           = from_seq._jet_algorithm          ;
+  _plugin_activated        = from_seq._plugin_activated       ;
+
+  // the data
+  _jets     = from_seq._jets;
+  _history  = from_seq._history;
+  // the following transferse ownership of the extras from the from_seq
+  _extras   = from_seq._extras;
+
+}
+
+//----------------------------------------------------------------------
+// record an ij recombination and reset the _jets[newjet_k] momentum and
+// user index to be those of newjet
+void ClusterSequence::plugin_record_ij_recombination(
+	   int jet_i, int jet_j, double dij, 
+	   const PseudoJet & newjet, int & newjet_k) {
+
+  plugin_record_ij_recombination(jet_i, jet_j, dij, newjet_k);
+
+  // now transfer newjet into place
+  int tmp_index = _jets[newjet_k].cluster_hist_index();
+  _jets[newjet_k] = newjet;
+  _jets[newjet_k].set_cluster_hist_index(tmp_index);
+}
+
+
+//----------------------------------------------------------------------
+// return all inclusive jets with pt > ptmin
+vector<PseudoJet> ClusterSequence::inclusive_jets (const double & ptmin) const{
+  double dcut = ptmin*ptmin;
+  int i = _history.size() - 1; // last jet
+  vector<PseudoJet> jets;
+  if (_jet_algorithm == kt_algorithm) {
+    while (i >= 0) {
+      // with our specific definition of dij and diB (i.e. R appears only in 
+      // dij), then dij==diB is the same as the jet.perp2() and we can exploit
+      // this in selecting the jets...
+      if (_history[i].max_dij_so_far < dcut) {break;}
+      if (_history[i].parent2 == BeamJet && _history[i].dij >= dcut) {
+	// for beam jets
+	int parent1 = _history[i].parent1;
+	jets.push_back(_jets[_history[parent1].jetp_index]);}
+      i--;
+    }
+  } else if (_jet_algorithm == cambridge_algorithm) {
+    while (i >= 0) {
+      // inclusive jets are all at end of clustering sequence in the
+      // Cambridge algorithm -- so if we find a non-exclusive jet, then
+      // we can exit
+      if (_history[i].parent2 != BeamJet) {break;}
+      int parent1 = _history[i].parent1;
+      const PseudoJet & jet = _jets[_history[parent1].jetp_index];
+      if (jet.perp2() >= dcut) {jets.push_back(jet);}
+      i--;
+    }
+  } else if (_jet_algorithm == plugin_algorithm 
+             || _jet_algorithm == antikt_algorithm
+             || _jet_algorithm == cambridge_for_passive_algorithm) {
+    // for inclusive jets with a plugin algorithm, we make no
+    // assumptions about anything (relation of dij to momenta,
+    // ordering of the dij, etc.)
+    while (i >= 0) {
+      if (_history[i].parent2 == BeamJet) {
+	int parent1 = _history[i].parent1;
+	const PseudoJet & jet = _jets[_history[parent1].jetp_index];
+	if (jet.perp2() >= dcut) {jets.push_back(jet);}
+      }
+      i--;
+    }
+  } else {throw Error("Unrecognized jet algorithm");}
+  return jets;
+}
+
+
+//----------------------------------------------------------------------
+// return the number of exclusive jets that would have been obtained
+// running the algorithm in exclusive mode with the given dcut
+int ClusterSequence::n_exclusive_jets (const double & dcut) const {
+
+  // first locate the point where clustering would have stopped (i.e. the
+  // first time max_dij_so_far > dcut)
+  int i = _history.size() - 1; // last jet
+  while (i >= 0) {
+    if (_history[i].max_dij_so_far <= dcut) {break;}
+    i--;
+  }
+  int stop_point = i + 1;
+  // relation between stop_point, njets assumes one extra jet disappears
+  // at each clustering.
+  int njets = 2*_initial_n - stop_point;
+  return njets;
+}
+
+//----------------------------------------------------------------------
+// return all exclusive jets that would have been obtained running
+// the algorithm in exclusive mode with the given dcut
+vector<PseudoJet> ClusterSequence::exclusive_jets (const double & dcut) const {
+  int njets = n_exclusive_jets(dcut);
+  return exclusive_jets(njets);
+}
+
+
+//----------------------------------------------------------------------
+// return the jets obtained by clustering the event to n jets.
+vector<PseudoJet> ClusterSequence::exclusive_jets (const int & njets) const {
+
+  // make sure the user does not ask for more than jets than there
+  // were particles in the first place.
+  assert (njets <= _initial_n);
+
+  // provide a warning when extracting exclusive jets 
+  if (_jet_def.jet_algorithm() != kt_algorithm && _n_exclusive_warnings < 5) {
+    _n_exclusive_warnings++;
+    cerr << "FastJet WARNING: dcut and exclusive jets for jet-finders other than kt should be interpreted with care." << endl;
+  }
+
+
+  // calculate the point where we have to stop the clustering.
+  // relation between stop_point, njets assumes one extra jet disappears
+  // at each clustering.
+  int stop_point = 2*_initial_n - njets;
+
+  // some sanity checking to make sure that e+e- does not give us
+  // surprises (should we ever implement e+e-)...
+  if (2*_initial_n != static_cast<int>(_history.size())) {
+    ostringstream err;
+    err << "2*_initial_n != _history.size() -- this endangers internal assumptions!\n";
+    throw Error(err.str());
+    //assert(false);
+  }
+
+  // now go forwards and reconstitute the jets that we have --
+  // basically for any history element, see if the parent jets to
+  // which it refers were created before the stopping point -- if they
+  // were then add them to the list, otherwise they are subsequent
+  // recombinations of the jets that we are looking for.
+  vector<PseudoJet> jets;
+  for (unsigned int i = stop_point; i < _history.size(); i++) {
+    int parent1 = _history[i].parent1;
+    if (parent1 < stop_point) {
+      jets.push_back(_jets[_history[parent1].jetp_index]);
+    }
+    int parent2 = _history[i].parent2;
+    if (parent2 < stop_point && parent2 > 0) {
+      jets.push_back(_jets[_history[parent2].jetp_index]);
+    }
+    
+  }
+
+  // sanity check...
+  if (static_cast<int>(jets.size()) != njets) {
+    ostringstream err;
+    err << "ClusterSequence::exclusive_jets: size of returned vector ("
+	 <<jets.size()<<") does not coincide with requested number of jets ("
+	 <<njets<<")";
+    throw Error(err.str());
+  }
+
+  return jets;
+}
+
+//----------------------------------------------------------------------
+/// return the dmin corresponding to the recombination that went from
+/// n+1 to n jets
+double ClusterSequence::exclusive_dmerge (const int & njets) const {
+  assert(njets >= 0);
+  if (njets >= _initial_n) {return 0.0;}
+  return _history[2*_initial_n-njets-1].dij;
+}
+
+
+//----------------------------------------------------------------------
+/// return the maximum of the dmin encountered during all recombinations 
+/// up to the one that led to an n-jet final state; identical to
+/// exclusive_dmerge, except in cases where the dmin do not increase
+/// monotonically.
+double ClusterSequence::exclusive_dmerge_max (const int & njets) const {
+  assert(njets >= 0);
+  if (njets >= _initial_n) {return 0.0;}
+  return _history[2*_initial_n-njets-1].max_dij_so_far;
+}
+
+
+//----------------------------------------------------------------------
+// work through the object's history until
+bool ClusterSequence::object_in_jet(const PseudoJet & object, 
+                                    const PseudoJet & jet) const {
+
+  // make sure the object conceivably belongs to this clustering
+  // sequence
+  assert(_potentially_valid(object) && _potentially_valid(jet));
+
+  const PseudoJet * this_object = &object;
+  const PseudoJet * childp;
+  while(true) {
+    if (this_object->cluster_hist_index() == jet.cluster_hist_index()) {
+      return true;
+    } else if (has_child(*this_object, childp)) {this_object = childp;}
+    else {return false;}
+  }
+}
+
+//----------------------------------------------------------------------
+/// if the jet has parents in the clustering, it returns true
+/// and sets parent1 and parent2 equal to them.
+///
+/// if it has no parents it returns false and sets parent1 and
+/// parent2 to zero
+bool ClusterSequence::has_parents(const PseudoJet & jet, PseudoJet & parent1, 
+                              PseudoJet & parent2) const {
+
+  const history_element & hist = _history[jet.cluster_hist_index()];
+
+  // make sure we do not run into any unexpected situations --
+  // i.e. both parents valid, or neither
+  assert ((hist.parent1 >= 0 && hist.parent2 >= 0) || 
+          (hist.parent1 < 0 && hist.parent2 < 0));
+
+  if (hist.parent1 < 0) {
+    parent1 = PseudoJet(0.0,0.0,0.0,0.0);
+    parent2 = parent1;
+    return false;
+  } else {
+    parent1 = _jets[_history[hist.parent1].jetp_index];
+    parent2 = _jets[_history[hist.parent2].jetp_index];
+    // order the parents in decreasing pt
+    if (parent1.perp2() < parent2.perp2()) swap(parent1,parent2);
+    return true;
+  }
+}
+
+//----------------------------------------------------------------------
+/// if the jet has a child then return true and give the child jet
+/// otherwise return false and set the child to zero
+bool ClusterSequence::has_child(const PseudoJet & jet, PseudoJet & child) const {
+
+  //const history_element & hist = _history[jet.cluster_hist_index()];
+  //
+  //if (hist.child >= 0) {
+  //  child = _jets[_history[hist.child].jetp_index];
+  //  return true;
+  //} else {
+  //  child = PseudoJet(0.0,0.0,0.0,0.0);
+  //  return false;
+  //}
+  const PseudoJet * childp;
+  bool res = has_child(jet, childp);
+  if (res) {
+    child = *childp;
+    return true;
+  } else {
+    child = PseudoJet(0.0,0.0,0.0,0.0);
+    return false;
+  }
+}
+
+bool ClusterSequence::has_child(const PseudoJet & jet, const PseudoJet * & childp) const {
+
+  const history_element & hist = _history[jet.cluster_hist_index()];
+
+  // check that this jet has a child and that the child corresponds to
+  // a true jet [RETHINK-IF-CHANGE-NUMBERING: what is the right
+  // behaviour if the child is the same jet but made inclusive...?]
+  if (hist.child >= 0 && _history[hist.child].jetp_index >= 0) {
+    childp = &(_jets[_history[hist.child].jetp_index]);
+    return true;
+  } else {
+    childp = NULL;
+    return false;
+  }
+}
+
+
+//----------------------------------------------------------------------
+/// if this jet has a child (and so a partner) return true
+/// and give the partner, otherwise return false and set the
+/// partner to zero
+bool ClusterSequence::has_partner(const PseudoJet & jet, 
+                              PseudoJet & partner) const {
+
+  const history_element & hist = _history[jet.cluster_hist_index()];
+
+  // make sure we have a child and that the child does not correspond
+  // to a clustering with the beam (or some other invalid quantity)
+  if (hist.child >= 0 && _history[hist.child].parent2 >= 0) {
+    const history_element & child_hist = _history[hist.child];
+    if (child_hist.parent1 == jet.cluster_hist_index()) {
+      // partner will be child's parent2 -- for iB clustering
+      // parent2 will not be valid
+      partner = _jets[_history[child_hist.parent2].jetp_index];
+    } else {
+      // partner will be child's parent1
+      partner = _jets[_history[child_hist.parent1].jetp_index];
+    }
+    return true;
+  } else {
+    partner = PseudoJet(0.0,0.0,0.0,0.0);
+    return false;
+  }
+}
+
+
+//----------------------------------------------------------------------
+// return a vector of the particles that make up a jet
+vector<PseudoJet> ClusterSequence::constituents (const PseudoJet & jet) const {
+  vector<PseudoJet> subjets;
+  add_constituents(jet, subjets);
+  return subjets;
+}
+
+//----------------------------------------------------------------------
+/// output the supplied vector of jets in a format that can be read
+/// by an appropriate root script; the format is:
+/// jet-n jet-px jet-py jet-pz jet-E 
+///   particle-n particle-rap particle-phi particle-pt
+///   particle-n particle-rap particle-phi particle-pt
+///   ...
+/// #END
+/// ... [i.e. above repeated]
+void ClusterSequence::print_jets_for_root(const std::vector<PseudoJet> & jets, 
+                                          ostream & ostr) const {
+  for (unsigned i = 0; i < jets.size(); i++) {
+    ostr << i  << " "
+         << jets[i].px() << " "
+         << jets[i].py() << " "
+         << jets[i].pz() << " "
+         << jets[i].E() << endl;
+    vector<PseudoJet> cst = constituents(jets[i]);
+    for (unsigned j = 0; j < cst.size() ; j++) {
+      ostr << " " << j << " "
+           << cst[j].rap() << " "
+           << cst[j].phi() << " "
+           << cst[j].perp() << endl;
+    }
+    ostr << "#END" << endl;
+  }
+}
+
+// Not yet. Perhaps in a future release
+// //----------------------------------------------------------------------
+// // print out all inclusive jets with pt > ptmin
+// void ClusterSequence::print_jets (const double & ptmin) const{
+//     vector<PseudoJet> jets = sorted_by_pt(inclusive_jets(ptmin));
+// 
+//     for (size_t j = 0; j < jets.size(); j++) {
+//        printf("%5u %7.3f %7.3f %9.3f\n",
+//        j,jets[j].rap(),jets[j].phi(),jets[j].perp());
+//     }
+// }
+
+//----------------------------------------------------------------------
+/// returns a vector of size n_particles() which indicates, for 
+/// each of the initial particles (in the order in which they were
+/// supplied), which of the supplied jets it belongs to; if it does
+/// not belong to any of the supplied jets, the index is set to -1;
+vector<int> ClusterSequence::particle_jet_indices(
+                        const vector<PseudoJet> & jets) const {
+
+  vector<int> indices(n_particles());
+
+  // first label all particles as not belonging to any jets
+  for (unsigned ipart = 0; ipart < n_particles(); ipart++) 
+    indices[ipart] = -1;
+
+  // then for each of the jets relabel its consituents as belonging to
+  // that jet
+  for (unsigned ijet = 0; ijet < jets.size(); ijet++) {
+
+    vector<PseudoJet> jet_constituents(constituents(jets[ijet]));
+
+    for (unsigned ip = 0; ip < jet_constituents.size(); ip++) {
+      // a safe (if slightly redundant) way of getting the particle
+      // index (for initial particles it is actually safe to assume
+      // ipart=iclust).
+      unsigned iclust = jet_constituents[ip].cluster_hist_index();
+      unsigned ipart = history()[iclust].jetp_index;
+      indices[ipart] = ijet;
+    }
+  }
+
+  return indices;
+}
+
+
+//----------------------------------------------------------------------
+// recursive routine that adds on constituents of jet to the subjet_vector
+void ClusterSequence::add_constituents (
+           const PseudoJet & jet, vector<PseudoJet> & subjet_vector) const {
+  // find out position in cluster history
+  int i = jet.cluster_hist_index();
+  int parent1 = _history[i].parent1;
+  int parent2 = _history[i].parent2;
+
+  if (parent1 == InexistentParent) {
+    // It is an original particle (labelled by its parent having value
+    // InexistentParent), therefore add it on to the subjet vector
+    subjet_vector.push_back(jet);
+    return;
+  } 
+
+  // add parent 1
+  add_constituents(_jets[_history[parent1].jetp_index], subjet_vector);
+
+  // see if parent2 is a real jet; if it is then add its constituents
+  if (parent2 != BeamJet) {
+    add_constituents(_jets[_history[parent2].jetp_index], subjet_vector);
+  }
+}
+
+
+
+//----------------------------------------------------------------------
+// initialise the history in a standard way
+void ClusterSequence::_add_step_to_history (
+	       const int & step_number, const int & parent1, 
+	       const int & parent2, const int & jetp_index,
+	       const double & dij) {
+
+  history_element element;
+  element.parent1 = parent1;
+  element.parent2 = parent2;
+  element.jetp_index = jetp_index;
+  element.child = Invalid;
+  element.dij   = dij;
+  element.max_dij_so_far = max(dij,_history[_history.size()-1].max_dij_so_far);
+  _history.push_back(element);
+
+  int local_step = _history.size()-1;
+  assert(local_step == step_number);
+
+  assert(parent1 >= 0);
+  _history[parent1].child = local_step;
+  if (parent2 >= 0) {_history[parent2].child = local_step;}
+
+  // get cross-referencing right from PseudoJets
+  if (jetp_index != Invalid) {
+    assert(jetp_index >= 0);
+    //cout << _jets.size() <<" "<<jetp_index<<"\n";
+    _jets[jetp_index].set_cluster_hist_index(local_step);
+  }
+
+  if (_writeout_combinations) {
+    cout << local_step << ": " 
+	 << parent1 << " with " << parent2
+	 << "; y = "<< dij<<endl;
+  }
+
+}
+
+
+
+
+//======================================================================
+// Return an order in which to read the history such that _history[order[i]] 
+// will always correspond to the same set of consituent particles if 
+// two branching histories are equivalent in terms of the particles
+// contained in any given pseudojet.
+vector<int> ClusterSequence::unique_history_order() const {
+
+  // first construct an array that will tell us the lowest constituent
+  // of a given jet -- this will always be one of the original
+  // particles, whose order is well defined and so will help us to
+  // follow the tree in a unique manner.
+  valarray<int> lowest_constituent(_history.size());
+  int hist_n = _history.size();
+  lowest_constituent = hist_n; // give it a large number
+  for (int i = 0; i < hist_n; i++) {
+    // sets things up for the initial partons
+    lowest_constituent[i] = min(lowest_constituent[i],i); 
+    // propagates them through to the children of this parton
+    if (_history[i].child > 0) lowest_constituent[_history[i].child] 
+      = min(lowest_constituent[_history[i].child],lowest_constituent[i]);
+  }
+
+  // establish an array for what we have and have not extracted so far
+  valarray<bool> extracted(_history.size()); extracted = false;
+  vector<int> unique_tree;
+  unique_tree.reserve(_history.size());
+
+  // now work our way through the tree
+  for (unsigned i = 0; i < n_particles(); i++) {
+    if (!extracted[i]) {
+      unique_tree.push_back(i);
+      extracted[i] = true;
+      _extract_tree_children(i, extracted, lowest_constituent, unique_tree);
+    }
+  }
+
+  return unique_tree;
+}
+
+//======================================================================
+// helper for unique_history_order
+void ClusterSequence::_extract_tree_children(
+       int position, 
+       valarray<bool> & extracted, 
+       const valarray<int> & lowest_constituent,
+       vector<int> & unique_tree) const {
+  if (!extracted[position]) {
+    // that means we may have unidentified parents around, so go and
+    // collect them (extracted[position]) will then be made true)
+    _extract_tree_parents(position,extracted,lowest_constituent,unique_tree);
+  } 
+  
+  // now look after the children...
+  int child = _history[position].child;
+  if (child  >= 0) _extract_tree_children(child,extracted,lowest_constituent,unique_tree);
+}
+
+
+//======================================================================
+// return the list of unclustered particles
+vector<PseudoJet> ClusterSequence::unclustered_particles() const {
+  vector<PseudoJet> unclustered;
+  for (unsigned i = 0; i < n_particles() ; i++) {
+    if (_history[i].child == Invalid) 
+      unclustered.push_back(_jets[_history[i].jetp_index]);
+  }
+  return unclustered;
+}
+
+
+
+//======================================================================
+// helper for unique_history_order
+void ClusterSequence::_extract_tree_parents(
+       int position, 
+       valarray<bool> & extracted, 
+       const valarray<int> & lowest_constituent,
+       vector<int> & unique_tree) const {
+
+  if (!extracted[position]) {
+    int parent1 = _history[position].parent1;
+    int parent2 = _history[position].parent2;
+    // where relevant order parents so that we will first treat the
+    // one containing the smaller "lowest_constituent"
+    if (parent1 >= 0 && parent2 >= 0) {
+      if (lowest_constituent[parent1] > lowest_constituent[parent2]) 
+	swap(parent1, parent2);
+    }
+    // then actually run through the parents to extract the constituents...
+    if (parent1 >= 0 && !extracted[parent1]) 
+      _extract_tree_parents(parent1,extracted,lowest_constituent,unique_tree);
+    if (parent2 >= 0 && !extracted[parent2]) 
+      _extract_tree_parents(parent2,extracted,lowest_constituent,unique_tree);
+    // finally declare this position to be accounted for and push it
+    // onto our list.
+    unique_tree.push_back(position);
+    extracted[position] = true;
+  }
+}
+
+
+//======================================================================
+/// carries out the bookkeeping associated with the step of recombining
+/// jet_i and jet_j (assuming a distance dij) and returns the index
+/// of the recombined jet, newjet_k.
+void ClusterSequence::_do_ij_recombination_step(
+                               const int & jet_i, const int & jet_j, 
+			       const double & dij, 
+			       int & newjet_k) {
+
+  // create the new jet by recombining the first two
+  PseudoJet newjet;
+  _jet_def.recombiner()->recombine(_jets[jet_i], _jets[jet_j], newjet);
+  _jets.push_back(newjet);
+  // original version...
+  //_jets.push_back(_jets[jet_i] + _jets[jet_j]);
+
+  // get its index
+  newjet_k = _jets.size()-1;
+
+  // get history index
+  int newstep_k = _history.size();
+  // and provide jet with the info
+  _jets[newjet_k].set_cluster_hist_index(newstep_k);
+
+  // finally sort out the history 
+  int hist_i = _jets[jet_i].cluster_hist_index();
+  int hist_j = _jets[jet_j].cluster_hist_index();
+
+  _add_step_to_history(newstep_k, min(hist_i, hist_j), max(hist_i,hist_j),
+		       newjet_k, dij);
+
+}
+
+
+//======================================================================
+/// carries out the bookkeeping associated with the step of recombining
+/// jet_i with the beam
+void ClusterSequence::_do_iB_recombination_step(
+				  const int & jet_i, const double & diB) {
+  // get history index
+  int newstep_k = _history.size();
+
+  // recombine the jet with the beam
+  _add_step_to_history(newstep_k,_jets[jet_i].cluster_hist_index(),BeamJet,
+		       Invalid, diB);
+
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequence1GhostPassiveArea.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence1GhostPassiveArea.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence1GhostPassiveArea.cc	(revision 11)
@@ -0,0 +1,102 @@
+//STARTHEADER
+// $Id: ClusterSequence1GhostPassiveArea.cc,v 1.1 2008-11-06 14:32:13 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/ClusterSequence1GhostPassiveArea.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+using namespace std;
+
+//----------------------------------------------------------------------
+/// global routine for initialising and running a general passive area
+void ClusterSequence1GhostPassiveArea::_initialise_and_run_1GPA (
+		const JetDefinition & jet_def,
+		const GhostedAreaSpec & area_spec,
+		const bool & writeout_combinations) {
+
+  bool continue_running;
+  _initialise_AA(jet_def,  area_spec, writeout_combinations, continue_running);
+  if (continue_running) {
+    _run_1GPA(area_spec);
+    _postprocess_AA(area_spec);
+  }
+}
+
+
+//----------------------------------------------------------------------
+/// routine for running a passive area one ghost at a time.
+void ClusterSequence1GhostPassiveArea::_run_1GPA (const GhostedAreaSpec & area_spec) {
+    // record the input jets as they are currently
+  vector<PseudoJet> input_jets(_jets);
+
+  // code for testing the unique tree
+  vector<int> unique_tree;
+
+  // initialise our temporary average area^2
+  valarray<double> lcl_average_area2(0.0, _average_area.size());
+  valarray<double> last_average_area(0.0, _average_area.size());
+
+  // run the clustering multiple times so as to get areas of all the jets
+  for (int irepeat = 0; irepeat < area_spec.repeat(); irepeat++) {
+
+    // first establish list of all ghosts
+    vector<PseudoJet> all_ghosts;
+    area_spec.add_ghosts(all_ghosts);
+
+    // then run many subsets of ghosts (actually each subset contains just one ghost)
+    for (unsigned ig = 0; ig < all_ghosts.size(); ig++) {
+      vector<PseudoJet> some_ghosts;
+      some_ghosts.push_back(all_ghosts[ig]);
+      ClusterSequenceActiveAreaExplicitGhosts clust_seq(input_jets, jet_def(), 
+                                                       some_ghosts, area_spec.actual_ghost_area());
+
+      if (irepeat == 0 && ig == 0) {
+        // take the non-ghost part of the history and put into our own
+        // history.
+        _transfer_ghost_free_history(clust_seq);
+        // get the "unique" order that will be used for transferring all areas. 
+        unique_tree = unique_history_order();
+      }
+      
+      // transfer areas from clust_seq into our object
+      _transfer_areas(unique_tree, clust_seq);
+    }
+    // keep track of fluctuations in area
+    lcl_average_area2 += (_average_area - last_average_area)*
+                         (_average_area - last_average_area);
+    last_average_area = _average_area;
+  }
+  _average_area2 = lcl_average_area2;
+}
+
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequenceActiveArea.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequenceActiveArea.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequenceActiveArea.cc	(revision 11)
@@ -0,0 +1,773 @@
+//STARTHEADER
+// $Id: ClusterSequenceActiveArea.cc,v 1.1 2008-11-06 14:32:13 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/PseudoJet.hh"
+#include "../include/fastjet/ClusterSequence.hh"
+#include "../include/fastjet/ClusterSequenceActiveArea.hh"
+#include "../include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
+#include<iostream>
+#include<vector>
+#include<sstream>
+#include<algorithm>
+#include<cmath>
+#include<valarray>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+using namespace std;
+
+
+//int ClusterSequenceActiveArea::_n_seed_warnings = 0;
+//const int _max_seed_warnings = 10;
+
+//----------------------------------------------------------------------
+/// global routine for running active area
+void ClusterSequenceActiveArea::_initialise_and_run_AA (
+		const JetDefinition & jet_def,
+		const GhostedAreaSpec & area_spec,
+		const bool & writeout_combinations) {
+
+  bool continue_running;
+  _initialise_AA(jet_def,  area_spec, writeout_combinations, continue_running);
+  if (continue_running) {
+    _run_AA(area_spec);
+    _postprocess_AA(area_spec);
+  }
+}
+
+//----------------------------------------------------------------------
+void ClusterSequenceActiveArea::_resize_and_zero_AA () {
+  // initialize our local area information
+  _average_area.resize(2*_jets.size());  _average_area  = 0.0;
+  _average_area2.resize(2*_jets.size()); _average_area2 = 0.0;
+  _average_area_4vector.resize(2*_jets.size()); 
+  _average_area_4vector = PseudoJet(0.0,0.0,0.0,0.0);
+  _non_jet_area = 0.0; _non_jet_area2 = 0.0; _non_jet_number=0.0;
+}
+
+//---------------------------------a-------------------------------------
+void ClusterSequenceActiveArea::_initialise_AA (
+		const JetDefinition & jet_def,
+		const GhostedAreaSpec & area_spec,
+		const bool & writeout_combinations,
+                bool & continue_running) 
+{
+
+  // store this for future use
+  _area_spec_repeat = area_spec.repeat();
+
+  // make sure placeholders are there & zeroed
+  _resize_and_zero_AA();
+     
+  // for future reference...
+  _maxrap_for_area = area_spec.ghost_maxrap();
+  _safe_rap_for_area = _maxrap_for_area - jet_def.R();
+
+  // Make sure we'll have at least one repetition -- then we can
+  // deduce the unghosted clustering sequence from one of the ghosted
+  // sequences. If we do not have any repetitions, then get the
+  // unghosted sequence from the plain unghosted clustering.
+  //
+  // NB: all decanting and filling of initial history will then
+  // be carried out by base-class routine
+  if (area_spec.repeat() <= 0) {
+    _initialise_and_run(jet_def, writeout_combinations);
+    continue_running = false;
+    return;
+  }
+
+  // transfer all relevant info into internal variables
+  _decant_options(jet_def, writeout_combinations);
+
+  // set up the history entries for the initial particles (those
+  // currently in _jets)
+  _fill_initial_history();
+
+  // by default it does not...
+  _has_dangerous_particles = false;
+  
+  continue_running = true;
+}
+
+
+//----------------------------------------------------------------------
+void ClusterSequenceActiveArea::_run_AA (const GhostedAreaSpec & area_spec) {
+  // record the input jets as they are currently
+  vector<PseudoJet> input_jets(_jets);
+
+  // code for testing the unique tree
+  vector<int> unique_tree;
+
+  // run the clustering multiple times so as to get areas of all the jets
+  for (int irepeat = 0; irepeat < area_spec.repeat(); irepeat++) {
+
+    ClusterSequenceActiveAreaExplicitGhosts clust_seq(input_jets, 
+                                                      jet_def(), area_spec);
+
+    _has_dangerous_particles |= clust_seq.has_dangerous_particles();
+    if (irepeat == 0) {
+      // take the non-ghost part of the history and put into our own
+      // history.
+      _transfer_ghost_free_history(clust_seq);
+      // get the "unique" order that will be used for transferring all areas. 
+      unique_tree = unique_history_order();
+    }
+
+    // transfer areas from clust_seq into our object
+    _transfer_areas(unique_tree, clust_seq);
+  }
+}
+  
+
+//----------------------------------------------------------------------
+/// run the postprocessing for the active area (and derived classes)
+void ClusterSequenceActiveArea::_postprocess_AA (const GhostedAreaSpec & area_spec) {
+  _average_area  /= area_spec.repeat();
+  _average_area2 /= area_spec.repeat();
+  if (area_spec.repeat() > 1) {
+    // the VC compiler complains if one puts everything on a single line.
+    // An alternative solution would be to use -1.0 (+single line)
+    const double tmp = area_spec.repeat()-1;
+    _average_area2 = sqrt(abs(_average_area2 - _average_area*_average_area)/tmp);
+  } else {
+    _average_area2 = 0.0;
+  }
+
+  _non_jet_area  /= area_spec.repeat();
+  _non_jet_area2 /= area_spec.repeat();
+  _non_jet_area2  = sqrt(abs(_non_jet_area2 - _non_jet_area*_non_jet_area)/
+			 area_spec.repeat());
+  _non_jet_number /= area_spec.repeat();
+
+  // following bizarre way of writing things is related to 
+  // poverty of operations on PseudoJet objects (as well as some confusion
+  // in one or two places)
+  for (unsigned i = 0; i < _average_area_4vector.size(); i++) {
+    _average_area_4vector[i] = (1.0/area_spec.repeat()) * _average_area_4vector[i];
+  }
+  //cerr << "Non-jet area = " << _non_jet_area << " +- " << _non_jet_area2<<endl;
+}
+
+
+// //----------------------------------------------------------------------
+// void ClusterSequenceActiveArea::_initialise_and_run_AA (
+// 		const JetDefinition & jet_def,
+// 		const GhostedAreaSpec & area_spec,
+// 		const bool & writeout_combinations) 
+// {
+// 
+//   // store this for future use
+//   _area_spec_repeat = area_spec.repeat();
+// 
+//   // initialize our local area information
+//   _average_area.resize(2*_jets.size());  _average_area  = 0.0;
+//   _average_area2.resize(2*_jets.size()); _average_area2 = 0.0;
+//   _average_area_4vector.resize(2*_jets.size()); 
+//   _average_area_4vector = PseudoJet(0.0,0.0,0.0,0.0);
+//   _non_jet_area = 0.0; _non_jet_area2 = 0.0; _non_jet_number=0.0;
+//      
+//   // for future reference...
+//   _maxrap_for_area = area_spec.ghost_maxrap();
+//   _safe_rap_for_area = _maxrap_for_area - jet_def.R();
+// 
+//   // Make sure we'll have at least one repetition -- then we can
+//   // deduce the unghosted clustering sequence from one of the ghosted
+//   // sequences. If we do not have any repetitions, then get the
+//   // unghosted sequence from the plain unghosted clustering.
+//   //
+//   // NB: all decanting and filling of initial history will then
+//   // be carried out by base-class routine
+//   if (area_spec.repeat() <= 0) {
+//     _initialise_and_run(jet_def, writeout_combinations);
+//     return;
+//   }
+// 
+//   // transfer all relevant info into internal variables
+//   _decant_options(jet_def, writeout_combinations);
+// 
+//   // set up the history entries for the initial particles (those
+//   // currently in _jets)
+//   _fill_initial_history();
+// 
+//   // record the input jets as they are currently
+//   vector<PseudoJet> input_jets(_jets);
+// 
+//   // code for testing the unique tree
+//   vector<int> unique_tree;
+// 
+//   
+//   
+// 
+//   // run the clustering multiple times so as to get areas of all the jets
+//   for (int irepeat = 0; irepeat < area_spec.repeat(); irepeat++) {
+// 
+//     ClusterSequenceActiveAreaExplicitGhosts clust_seq(input_jets, 
+//                                                       jet_def, area_spec);
+// 
+//     if (irepeat == 0) {
+//       // take the non-ghost part of the history and put into our own
+//       // history.
+//       _transfer_ghost_free_history(clust_seq);
+//       // get the "unique" order that will be used for transferring all areas. 
+//       unique_tree = unique_history_order();
+//     }
+// 
+//     // transfer areas from clust_seq into our object
+//     _transfer_areas(unique_tree, clust_seq);
+//   }
+//   
+//   _average_area  /= area_spec.repeat();
+//   _average_area2 /= area_spec.repeat();
+//   if (area_spec.repeat() > 1) {
+//     _average_area2 = sqrt(abs(_average_area2 - _average_area*_average_area)/
+//                           (area_spec.repeat()-1));
+//   } else {
+//     _average_area2 = 0.0;
+//   }
+// 
+//   _non_jet_area  /= area_spec.repeat();
+//   _non_jet_area2 /= area_spec.repeat();
+//   _non_jet_area2  = sqrt(abs(_non_jet_area2 - _non_jet_area*_non_jet_area)/
+// 			 area_spec.repeat());
+//   _non_jet_number /= area_spec.repeat();
+// 
+//   // following bizarre way of writing things is related to 
+//   // poverty of operations on PseudoJet objects (as well as some confusion
+//   // in one or two places)
+//   for (unsigned i = 0; i < _average_area_4vector.size(); i++) {
+//     _average_area_4vector[i] = (1.0/area_spec.repeat()) * _average_area_4vector[i];
+//   }
+//   //cerr << "Non-jet area = " << _non_jet_area << " +- " << _non_jet_area2<<endl;
+// 
+//   
+// }
+// 
+
+
+//----------------------------------------------------------------------
+double ClusterSequenceActiveArea::pt_per_unit_area(
+		       mean_pt_strategies strat, double range) const {
+  
+  vector<PseudoJet> incl_jets = inclusive_jets();
+  vector<double> pt_over_areas;
+
+  for (unsigned i = 0; i < incl_jets.size(); i++) {
+    if (abs(incl_jets[i].rap()) < _safe_rap_for_area) {
+      double this_area;
+      if ( strat == median_4vector ) {
+          this_area = area_4vector(incl_jets[i]).perp();
+      } else {
+          this_area = area(incl_jets[i]);
+      }
+      pt_over_areas.push_back(incl_jets[i].perp()/this_area);
+    }
+  }
+  
+  // there is nothing inside our region, so answer will always be zero
+  if (pt_over_areas.size() == 0) {return 0.0;}
+  
+  // get median (pt/area) [this is the "old" median definition. It considers
+  // only the "real" jets in calculating the median, i.e. excluding the
+  // only-ghost ones]
+  sort(pt_over_areas.begin(), pt_over_areas.end());
+  double non_ghost_median_ratio = pt_over_areas[pt_over_areas.size()/2];
+
+  // new median definition that takes into account non-jet area (i.e.
+  // jets composed only of ghosts), and for fractional median position 
+  // interpolates between the corresponding entries in the pt_over_areas array
+  double nj_median_pos = (pt_over_areas.size()-1 - _non_jet_number)/2.0;
+  double nj_median_ratio;
+  if (nj_median_pos >= 0 && pt_over_areas.size() > 1) {
+    int int_nj_median = int(nj_median_pos);
+    nj_median_ratio = 
+      pt_over_areas[int_nj_median] * (int_nj_median+1-nj_median_pos)
+      + pt_over_areas[int_nj_median+1] * (nj_median_pos - int_nj_median);
+  } else {
+    nj_median_ratio = 0.0;
+  }
+
+
+  // get various forms of mean (pt/area)
+  double pt_sum = 0.0, pt_sum_with_cut = 0.0;
+  double area_sum = _non_jet_area, area_sum_with_cut = _non_jet_area;
+  double ratio_sum = 0.0; 
+  double ratio_n = _non_jet_number;
+  for (unsigned i = 0; i < incl_jets.size(); i++) {
+    if (abs(incl_jets[i].rap()) < _safe_rap_for_area) {
+      double this_area;
+      if ( strat == median_4vector ) {
+          this_area = area_4vector(incl_jets[i]).perp();
+      } else {
+          this_area = area(incl_jets[i]);
+      }
+      pt_sum   += incl_jets[i].perp();
+      area_sum += this_area;
+      double ratio = incl_jets[i].perp()/this_area;
+      if (ratio < range*nj_median_ratio) {
+	pt_sum_with_cut   += incl_jets[i].perp();
+	area_sum_with_cut += this_area;
+	ratio_sum += ratio; ratio_n++;
+      }
+    }
+  }
+  
+  if (strat == play) {
+    double trunc_sum = 0, trunc_sumsqr = 0;
+    vector<double> means(pt_over_areas.size()), sd(pt_over_areas.size());
+    for (unsigned i = 0; i < pt_over_areas.size() ; i++ ) {
+      double ratio = pt_over_areas[i];
+      trunc_sum += ratio;
+      trunc_sumsqr += ratio*ratio;
+      means[i] = trunc_sum / (i+1);
+      sd[i]    = sqrt(abs(means[i]*means[i]  - trunc_sumsqr/(i+1)));
+      cerr << "i, means, sd: " <<i<<", "<< means[i] <<", "<<sd[i]<<", "<<
+	sd[i]/sqrt(i+1.0)<<endl;
+    }
+    cout << "-----------------------------------"<<endl;
+    for (unsigned i = 0; i <= pt_over_areas.size()/2 ; i++ ) {
+      cout << "Median "<< i <<" = " << pt_over_areas[i]<<endl;
+    }
+    cout << "Number of non-jets: "<<_non_jet_number<<endl;
+    cout << "Area of non-jets: "<<_non_jet_area<<endl;
+    cout << "Default median position: " << (pt_over_areas.size()-1)/2.0<<endl;
+    cout << "NJ median position: " << nj_median_pos <<endl;
+    cout << "NJ median value: " << nj_median_ratio <<endl;
+    return 0.0;
+  }
+
+  switch(strat) {
+  case median:
+  case median_4vector:
+    return nj_median_ratio;
+  case non_ghost_median:
+    return non_ghost_median_ratio; 
+  case pttot_over_areatot:
+    return pt_sum / area_sum;
+  case pttot_over_areatot_cut:
+    return pt_sum_with_cut / area_sum_with_cut;
+  case mean_ratio_cut:
+    return ratio_sum/ratio_n;
+  default:
+    return nj_median_ratio;
+  }
+
+}
+
+
+// The following functionality is now provided by the base class
+// //----------------------------------------------------------------------
+// // fit a parabola to pt/area as a function of rapidity, using the
+// // formulae of CCN28-36 (which actually fits f = a+b*x^2)
+// void ClusterSequenceActiveArea::parabolic_pt_per_unit_area(
+//        double & a, double & b, double raprange, double exclude_above,
+//        bool use_area_4vector) const {
+//   
+//   double this_raprange;
+//   if (raprange <= 0) {this_raprange = _safe_rap_for_area;}
+//   else {this_raprange = raprange;}
+// 
+//   int n=0;
+//   int n_excluded = 0;
+//   double mean_f=0, mean_x2=0, mean_x4=0, mean_fx2=0; 
+// 
+//   vector<PseudoJet> incl_jets = inclusive_jets();
+// 
+//   for (unsigned i = 0; i < incl_jets.size(); i++) {
+//     if (abs(incl_jets[i].rap()) < this_raprange) {
+//       double this_area;
+//       if ( use_area_4vector ) {
+//           this_area = area_4vector(incl_jets[i]).perp();     
+//       } else {
+//           this_area = area(incl_jets[i]);
+//       }
+//       double f = incl_jets[i].perp()/this_area;
+//       if (exclude_above <= 0.0 || f < exclude_above) {
+// 	double x = incl_jets[i].rap(); double x2 = x*x;
+// 	mean_f   += f;
+// 	mean_x2  += x2;
+// 	mean_x4  += x2*x2;
+// 	mean_fx2 += f*x2;
+// 	n++;
+//       } else {
+// 	n_excluded++;
+//       }
+//     }
+//   }
+// 
+//   if (n <= 1) {
+//     // meaningful results require at least two jets inside the
+//     // area -- mind you if there are empty jets we should be in 
+//     // any case doing something special...
+//     a = 0.0;
+//     b = 0.0;
+//   } else {
+//     mean_f   /= n;
+//     mean_x2  /= n;
+//     mean_x4  /= n;
+//     mean_fx2 /= n;
+//     
+//     b = (mean_f*mean_x2 - mean_fx2)/(mean_x2*mean_x2 - mean_x4);
+//     a = mean_f - b*mean_x2;
+//   }
+//   //cerr << "n_excluded = "<< n_excluded << endl;
+// }
+
+
+//----------------------------------------------------------------------
+double ClusterSequenceActiveArea::empty_area(const RangeDefinition & range) const {
+  double empty = 0.0;
+  // first deal with ghost jets
+  for (unsigned  i = 0; i < _ghost_jets.size(); i++) {
+    if (range.is_in_range(_ghost_jets[i])) {
+      empty += _ghost_jets[i].area;
+    }
+  }
+  // then deal with unclustered ghosts
+  for (unsigned  i = 0; i < _unclustered_ghosts.size(); i++) {
+    if (range.is_in_range(_unclustered_ghosts[i])) {
+      empty += _unclustered_ghosts[i].area;
+    }
+  }
+  empty /= _area_spec_repeat;
+  return empty;
+}
+
+//----------------------------------------------------------------------
+double ClusterSequenceActiveArea::n_empty_jets(const RangeDefinition & range) const {
+  double inrange = 0;
+  for (unsigned  i = 0; i < _ghost_jets.size(); i++) {
+    if (range.is_in_range(_ghost_jets[i])) inrange++;
+  }
+  inrange /= _area_spec_repeat;
+  return inrange;
+}
+
+//----------------------------------------------------------------------
+/// transfer the history (and jet-momenta) from clust_seq to our
+/// own internal structure while removing ghosts
+void ClusterSequenceActiveArea::_transfer_ghost_free_history(
+             const ClusterSequenceActiveAreaExplicitGhosts & ghosted_seq) {
+  
+  const vector<history_element> & gs_history  = ghosted_seq.history();
+  vector<int> gs2self_hist_map(gs_history.size());
+
+  // work our way through to first non-trivial combination
+  unsigned igs = 0;
+  unsigned iself = 0;
+  while (gs_history[igs].parent1 == InexistentParent) {
+    // record correspondence 
+    if (!ghosted_seq.is_pure_ghost(igs)) {
+      gs2self_hist_map[igs] = iself++; 
+    } else {
+      gs2self_hist_map[igs] = Invalid; 
+    }
+    igs++;
+  };
+
+  // make sure the count of non-ghost initial jets is equal to
+  // what we already have in terms of initial jets
+  assert(iself == _history.size());
+
+  // now actually transfer things
+  do  {
+    // if we are a pure ghost, then go on to next round
+    if (ghosted_seq.is_pure_ghost(igs)) {
+      gs2self_hist_map[igs] = Invalid;
+      continue;
+    }
+
+    const history_element & gs_hist_el = gs_history[igs];
+
+    bool parent1_is_ghost = ghosted_seq.is_pure_ghost(gs_hist_el.parent1);
+    bool parent2_is_ghost = ghosted_seq.is_pure_ghost(gs_hist_el.parent2);
+
+    // if exactly one parent is a ghost then maintain info about the
+    // non-ghost correspondence for this jet, and then go on to next
+    // recombination in the ghosted sequence
+    if (parent1_is_ghost && !parent2_is_ghost && gs_hist_el.parent2 >= 0) {
+      gs2self_hist_map[igs] = gs2self_hist_map[gs_hist_el.parent2];
+      continue;
+    }
+    if (!parent1_is_ghost && parent2_is_ghost) {
+      gs2self_hist_map[igs] = gs2self_hist_map[gs_hist_el.parent1];
+      continue;
+    }
+
+    // no parents are ghosts...
+    if (gs_hist_el.parent2 >= 0) {
+      // recombination of two non-ghosts
+      gs2self_hist_map[igs] = _history.size();
+      // record the recombination in our own sequence
+      int newjet_k; // dummy var -- not used
+      int jet_i = _history[gs2self_hist_map[gs_hist_el.parent1]].jetp_index;
+      int jet_j = _history[gs2self_hist_map[gs_hist_el.parent2]].jetp_index;
+      //cerr << "recombining "<< jet_i << " and "<< jet_j << endl;
+      _do_ij_recombination_step(jet_i, jet_j, gs_hist_el.dij, newjet_k);
+    } else {
+      // we have a non-ghost that has become a beam-jet
+      assert(gs_history[igs].parent2 == BeamJet);
+      // record position
+      gs2self_hist_map[igs] = _history.size();
+      // record the recombination in our own sequence
+      _do_iB_recombination_step(
+             _history[gs2self_hist_map[gs_hist_el.parent1]].jetp_index,
+             gs_hist_el.dij);
+    }
+  } while (++igs < gs_history.size());
+
+  // finally transfer info about strategy used (which isn't necessarily
+  // always the one that got asked for...)
+  _strategy = ghosted_seq.strategy_used();
+}
+
+//----------------------------------------------------------------------
+void ClusterSequenceActiveArea::_transfer_areas(
+	    const vector<int> & unique_hist_order,
+    	    const ClusterSequenceActiveAreaExplicitGhosts & ghosted_seq  ) {
+
+  const vector<history_element> & gs_history  = ghosted_seq.history();
+  const vector<PseudoJet>       & gs_jets     = ghosted_seq.jets();
+  vector<int>    gs_unique_hist_order = ghosted_seq.unique_history_order();
+
+  const double tolerance = 1e-11; // to decide when two jets are the same
+
+  int j = -1;
+  int hist_index = -1;
+  
+  valarray<double> our_areas(_history.size());
+  our_areas = 0.0;
+
+  valarray<PseudoJet> our_area_4vectors(_history.size());
+  our_area_4vectors = PseudoJet(0.0,0.0,0.0,0.0);
+
+  for (unsigned i = 0; i < gs_history.size(); i++) {
+    // only consider composite particles
+    unsigned gs_hist_index = gs_unique_hist_order[i];
+    if (gs_hist_index < ghosted_seq.n_particles()) continue;
+    const history_element & gs_hist = gs_history[gs_unique_hist_order[i]];
+    int parent1 = gs_hist.parent1;
+    int parent2 = gs_hist.parent2;
+
+    if (parent2 == BeamJet) {
+      // need to look at parent to get the actual jet
+      const PseudoJet & jet = 
+  	  gs_jets[gs_history[parent1].jetp_index];
+      double area = ghosted_seq.area(jet);
+      PseudoJet ext_area = ghosted_seq.area_4vector(jet);
+
+      if (ghosted_seq.is_pure_ghost(parent1)) {
+        // record the existence of the pure ghost jet for future use
+        _ghost_jets.push_back(GhostJet(jet,area));
+	if (abs(jet.rap()) < _safe_rap_for_area) {
+	  _non_jet_area  += area;
+	  _non_jet_area2 += area*area;
+	  _non_jet_number += 1;
+	}
+      } else {
+
+	// get next "combined-particle" index in our own history
+	// making sure we don't go beyond its bounds (if we do
+	// then we're in big trouble anyway...)
+	while (++j < int(_history.size())) {
+	  hist_index = unique_hist_order[j];
+	  if (hist_index >= _initial_n) break;}
+
+        // sanity checking -- do not overrun
+        if (j >= int(_history.size())) throw Error("ClusterSequenceActiveArea: overran reference array in diB matching");
+
+        // sanity check -- make sure we are taking about the same 
+        // jet in reference and new sequences
+        int refjet_index = _history[_history[hist_index].parent1].jetp_index;
+        assert(refjet_index >= 0 && refjet_index < int(_jets.size()));
+	const PseudoJet & refjet = _jets[refjet_index];
+
+      //cerr << "Inclusive" << endl;
+      //cerr << gs_history[parent1].jetp_index << " " << gs_jets.size() << endl;
+      //cerr << _history[_history[hist_index].parent1].jetp_index << " " << _jets.size() << endl;
+
+        // If pt disagrees check E; if they both disagree there's a
+        // problem here... NB: a massive particle with zero pt may
+        // have its pt changed when a ghost is added -- this is why we
+        // also require the energy to be wrong before complaining
+        _throw_unless_jets_have_same_perp_or_E(jet, refjet, tolerance,
+                                               ghosted_seq);
+
+	// set the area at this clustering stage
+	our_areas[hist_index]  = area; 
+	our_area_4vectors[hist_index]  = ext_area; 
+
+	// update the parent as well -- that way its area is the area
+	// immediately before clustering (i.e. resolve an ambiguity in
+	// the Cambridge case and ensure in the kt case that the original
+	// particles get a correct area)
+	our_areas[_history[hist_index].parent1] = area;
+	our_area_4vectors[_history[hist_index].parent1] = ext_area;
+	
+      }
+    }
+    else if (!ghosted_seq.is_pure_ghost(parent1) && 
+	     !ghosted_seq.is_pure_ghost(parent2)) {
+
+      // get next "combined-particle" index in our own history
+      while (++j < int(_history.size())) {
+	hist_index = unique_hist_order[j];
+	if (hist_index >= _initial_n) break;}
+      
+      // sanity checking -- do not overrun
+      if (j >= int(_history.size())) throw Error("ClusterSequenceActiveArea: overran reference array in dij matching");
+
+      // make sure that our reference history entry is also for
+      // an exclusive (dij) clustering (otherwise the comparison jet
+      // will not exist)
+      if (_history[hist_index].parent2 == BeamJet) throw Error("ClusterSequenceActiveArea: could not match clustering sequences (encountered dij matched with diB)");
+
+      //cerr << "Exclusive: hist_index,hist_size: " << hist_index << " " << _history.size()<< endl;
+      //cerr << gs_hist.jetp_index << " " << gs_jets.size() << endl;
+      //cerr << _history[hist_index].jetp_index << " " << _jets.size() << endl;
+
+      const PseudoJet & jet = gs_jets[gs_hist.jetp_index];
+      const PseudoJet & refjet = _jets[_history[hist_index].jetp_index];
+
+      // run sanity check 
+      _throw_unless_jets_have_same_perp_or_E(jet, refjet, tolerance,
+                                             ghosted_seq);
+
+      // update area and our local index (maybe redundant since later
+      // the descendants will reupdate it?)
+      double area  = ghosted_seq.area(jet);
+      our_areas[hist_index]  += area; 
+
+      PseudoJet ext_area = ghosted_seq.area_4vector(jet);
+
+      // GPS TMP debugging (jetclu) -----------------------
+      //ext_area = PseudoJet(1e-100,1e-100,1e-100,4e-100);
+      //our_area_4vectors[hist_index] = ext_area;
+      //cout << "aa " 
+      //     << our_area_4vectors[hist_index].px() << " "
+      //     << our_area_4vectors[hist_index].py() << " "
+      //     << our_area_4vectors[hist_index].pz() << " "
+      //     << our_area_4vectors[hist_index].E() << endl;
+      //cout << "bb " 
+      //     << ext_area.px() << " "
+      //     << ext_area.py() << " "
+      //     << ext_area.pz() << " "
+      //     << ext_area.E() << endl;
+      //---------------------------------------------------
+
+      _jet_def.recombiner()->plus_equal(our_area_4vectors[hist_index], ext_area);
+
+      // now update areas of parents (so that they becomes areas
+      // immediately before clustering occurred). This is of use
+      // because it allows us to set the areas of the original hard
+      // particles in the kt algorithm; for the Cambridge case it
+      // means a jet's area will be the area just before it clusters
+      // with another hard jet.
+      const PseudoJet & jet1 = gs_jets[gs_history[parent1].jetp_index];
+      int our_parent1 = _history[hist_index].parent1;
+      our_areas[our_parent1] = ghosted_seq.area(jet1);
+      our_area_4vectors[our_parent1] = ghosted_seq.area_4vector(jet1);
+
+      const PseudoJet & jet2 = gs_jets[gs_history[parent2].jetp_index];
+      int our_parent2 = _history[hist_index].parent2;
+      our_areas[our_parent2] = ghosted_seq.area(jet2);
+      our_area_4vectors[our_parent2] = ghosted_seq.area_4vector(jet2);
+    }
+
+  }
+
+  // now add unclustered ghosts to the relevant list so that we can
+  // calculate empty area later.
+  vector<PseudoJet> unclust = ghosted_seq.unclustered_particles();
+  for (unsigned iu = 0; iu < unclust.size();  iu++) {
+    if (ghosted_seq.is_pure_ghost(unclust[iu])) {
+      double area = ghosted_seq.area(unclust[iu]);
+      _unclustered_ghosts.push_back(GhostJet(unclust[iu],area));
+    }
+  }
+
+  /*
+   * WARNING:
+   *   _average_area has explicitly been sized initially to 2*jets().size()
+   *   which can be bigger than our_areas (of size _history.size()
+   *   if there are some unclustered particles. 
+   *   So we must take care about boundaries
+   */
+
+  for (unsigned int area_index = 0; area_index<our_areas.size(); area_index++){
+    _average_area[area_index]  += our_areas[area_index]; 
+    _average_area2[area_index] += our_areas[area_index]*our_areas[area_index]; 
+  }
+
+  //_average_area_4vector += our_area_4vectors;
+  // Use the proper recombination scheme when averaging the area_4vectors
+  // over multiple ghost runs (i.e. the repeat stage);
+  for (unsigned i = 0; i < our_area_4vectors.size(); i++) {
+    _jet_def.recombiner()->plus_equal(_average_area_4vector[i],
+                                       our_area_4vectors[i]);
+  }
+}
+
+
+/// check if two jets have the same momentum to within the
+/// tolerance (and if pt's are not the same we're forgiving and
+/// look to see if the energy is the same)
+void ClusterSequenceActiveArea::_throw_unless_jets_have_same_perp_or_E(
+                                const PseudoJet & jet, 
+                                const PseudoJet & refjet, 
+                                double tolerance,
+          const ClusterSequenceActiveAreaExplicitGhosts & jets_ghosted_seq
+) const {
+
+  if (abs(jet.perp2()-refjet.perp2()) > 
+      tolerance*max(jet.perp2(),refjet.perp2())
+      && abs(jet.E()-refjet.E()) > tolerance*max(jet.E(),refjet.E())) {
+    ostringstream ostr;
+    ostr << "Could not match clustering sequence for an inclusive/exclusive jet when reconstructing areas" << endl;
+    ostr << "  Ref-Jet: "
+         << refjet.px() << " " 
+         << refjet.py() << " " 
+         << refjet.pz() << " " 
+         << refjet.E() << endl;
+    ostr << "  New-Jet: "
+         << jet.px() << " " 
+         << jet.py() << " " 
+         << jet.pz() << " " 
+         << jet.E() << endl;
+    if (jets_ghosted_seq.has_dangerous_particles()) {
+      ostr << "  NB: some particles have pt too low wrt ghosts -- this may be the cause" << endl;}
+    //ostr << jet.perp() << " " << refjet.perp() << " "
+    //     << jet.perp() - refjet.perp() << endl;
+    throw Error(ostr.str());
+  }
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequenceActiveAreaExplicitGhosts.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequenceActiveAreaExplicitGhosts.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequenceActiveAreaExplicitGhosts.cc	(revision 11)
@@ -0,0 +1,179 @@
+//STARTHEADER
+// $Id: ClusterSequenceActiveAreaExplicitGhosts.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/ClusterSequenceActiveAreaExplicitGhosts.hh"
+#include<limits>
+
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+// save some typing
+typedef ClusterSequenceActiveAreaExplicitGhosts ClustSeqActAreaEG;
+
+
+LimitedWarning ClustSeqActAreaEG::_warnings;
+
+//----------------------------------------------------------------------
+///
+void ClustSeqActAreaEG::_add_ghosts (
+			 const GhostedAreaSpec & area_spec) {
+
+  // add the ghosts to the jets
+  area_spec.add_ghosts(_jets);
+
+  // now add labelling...
+  for (unsigned i = _initial_hard_n; i < _jets.size(); i++) {
+    //_jets[i].set_user_index(1);
+    _is_pure_ghost.push_back(true);
+  }
+
+  // and record some info from the area_spec
+  _ghost_area = area_spec.actual_ghost_area();
+  _n_ghosts   = area_spec.n_ghosts();
+}
+
+
+//----------------------------------------------------------------------
+// return the area of a jet
+double ClustSeqActAreaEG::area (const PseudoJet & jet) const {
+  return _areas[jet.cluster_hist_index()];
+}
+
+
+//----------------------------------------------------------------------
+// return the total area
+double ClustSeqActAreaEG::total_area () const {
+  return _n_ghosts * _ghost_area;
+}
+
+
+//----------------------------------------------------------------------
+// return the extended area of a jet
+PseudoJet ClustSeqActAreaEG::area_4vector (const PseudoJet & jet) const {
+  return _area_4vectors[jet.cluster_hist_index()];
+}
+
+//----------------------------------------------------------------------
+bool ClustSeqActAreaEG::is_pure_ghost(const PseudoJet & jet) const 
+{
+  return _is_pure_ghost[jet.cluster_hist_index()];
+}
+
+//----------------------------------------------------------------------
+bool ClustSeqActAreaEG::is_pure_ghost(int hist_ix) const 
+{
+  return hist_ix >= 0 ? _is_pure_ghost[hist_ix] : false;
+}
+
+//----------------------------------------------------------------------
+double ClustSeqActAreaEG::empty_area(const RangeDefinition & range) const {
+  vector<PseudoJet> unclust = unclustered_particles();
+  double area = 0.0;
+  for (unsigned iu = 0; iu < unclust.size();  iu++) {
+    if (is_pure_ghost(unclust[iu]) && range.is_in_range(unclust[iu])) {
+      area += _ghost_area;
+    }
+  }
+  return area;
+}
+
+//======================================================================
+// sort out the areas
+void ClustSeqActAreaEG::_post_process() {
+
+  // first check for danger signals.
+  // Establish largest ghost transverse momentum
+  _max_ghost_perp2 = 0.0;
+  for (int i = 0; i < _initial_n; i++) {
+    if (_is_pure_ghost[i] && _jets[i].perp2() > _max_ghost_perp2) 
+      _max_ghost_perp2 = _jets[i].perp2();
+  }
+
+  // now find out if any of the particles are close to danger
+  double danger_ratio = numeric_limits<double>::epsilon();
+  danger_ratio = danger_ratio * danger_ratio;
+  _has_dangerous_particles = false;
+  for (int i = 0; i < _initial_n; i++) {
+    if (!_is_pure_ghost[i] && 
+        danger_ratio * _jets[i].perp2() <=  _max_ghost_perp2) {
+      _has_dangerous_particles = true;
+      break;
+    }
+  }
+
+  if (_has_dangerous_particles) _warnings.warn("ClusterSequenceActiveAreaExplicitGhosts: \n  ghosts not sufficiently soft wrt some of the input particles\n  a common cause is (unphysical?) input particles with pt=0 but finite rapidity");
+
+  // sort out sizes
+  _areas.resize(_history.size());
+  _area_4vectors.resize(_history.size());
+  _is_pure_ghost.resize(_history.size());
+  
+  // First set up areas for the initial particles (ghost=_ghost_area,
+  // real particles = 0); recall that _initial_n here is the number of
+  // particles including ghosts
+  for (int i = 0; i < _initial_n; i++) {
+    if (_is_pure_ghost[i]) {
+      _areas[i] = _ghost_area;
+      // normalise pt to be _ghost_area (NB we make use of fact that
+      // for initial particles, jet and clust_hist index are the same).
+      _area_4vectors[i] = (_ghost_area/_jets[i].perp()) * _jets[i];
+    } else {
+      _areas[i] = 0;
+      _area_4vectors[i] = PseudoJet(0.0,0.0,0.0,0.0);
+    }
+  }
+  
+  // next follow the branching through and set up the areas 
+  // and ghost-nature at each step of the clustering (rather than
+  // each jet).
+  for (unsigned i = _initial_n; i < _history.size(); i++) {
+    if (_history[i].parent2 == BeamJet) {
+      _is_pure_ghost[i]  = _is_pure_ghost[_history[i].parent1];
+      _areas[i]          = _areas[_history[i].parent1];
+      _area_4vectors[i] = _area_4vectors[_history[i].parent1];
+    } else {
+      _is_pure_ghost[i]  = _is_pure_ghost[_history[i].parent1] && 
+	                   _is_pure_ghost[_history[i].parent2]   ;
+      _areas[i]          = _areas[_history[i].parent1] + 
+	                   _areas[_history[i].parent2]  ;			   
+      _jet_def.recombiner()->recombine(_area_4vectors[_history[i].parent1], 
+	                   _area_4vectors[_history[i].parent2],
+			   _area_4vectors[i]);	
+//      _area_4vectors[i] = _area_4vectors[_history[i].parent1] + 
+//                          _area_4vectors[_history[i].parent2]  ;
+    }
+
+  }
+  
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequenceArea.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequenceArea.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequenceArea.cc	(revision 11)
@@ -0,0 +1,25 @@
+#include "../include/fastjet/ClusterSequenceArea.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+LimitedWarning ClusterSequenceArea::_range_warnings;
+
+/// print a warning if the range is unsuitable for the current
+/// calculation of the area (e.g. because ghosts do not extend
+/// far enough).
+void ClusterSequenceArea::_warn_if_range_unsuitable(const RangeDefinition & range) const {
+  bool no_ghosts = (_area_def.area_type() == voronoi_area)
+    || (_area_def.area_type() == passive_area
+        && jet_def().jet_algorithm() == kt_algorithm);
+  if (! no_ghosts) {
+    double rapmin, rapmax;
+    range.get_rap_limits(rapmin, rapmax);
+    if (rapmin < -_area_def.ghost_spec().ghost_maxrap()+0.95*jet_def().R() ||
+        rapmax >  _area_def.ghost_spec().ghost_maxrap()-0.95*jet_def().R()) {
+      _range_warnings.warn("rapidity range for median (rho) extends beyond +-(ghost_maxrap - 0.95*R); this is likely to cause the results to be unreliable; safest option is to increase ghost_maxrap in the area definition");
+    }
+  }
+}
+
+
+FASTJET_END_NAMESPACE
Index: /trunk/Utilities/Fastjet/src/ClusterSequenceAreaBase.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequenceAreaBase.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequenceAreaBase.cc	(revision 11)
@@ -0,0 +1,306 @@
+
+//STARTHEADER
+// $Id: ClusterSequenceAreaBase.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+
+
+#include "../include/fastjet/ClusterSequenceAreaBase.hh"
+#include <algorithm>
+
+FASTJET_BEGIN_NAMESPACE
+
+using namespace std;
+
+
+/// allow for warnings
+LimitedWarning ClusterSequenceAreaBase::_warnings;
+
+//----------------------------------------------------------------------
+/// return the total area, within range, that is free of jets.
+/// 
+/// Calculate this as (range area) - \sum_{i in range} A_i
+///
+double ClusterSequenceAreaBase::empty_area(const RangeDefinition & range) const {
+  double empty = range.area();
+  vector<PseudoJet> incl_jets(inclusive_jets(0.0));
+  for (unsigned i = 0; i < incl_jets.size(); i++) {
+    if (range.is_in_range(incl_jets[i])) empty -= area(incl_jets[i]);
+  }
+  return empty;
+}
+
+double ClusterSequenceAreaBase::median_pt_per_unit_area(const RangeDefinition & range) const {
+  return median_pt_per_unit_something(range,false);
+}
+
+double ClusterSequenceAreaBase::median_pt_per_unit_area_4vector(const RangeDefinition & range) const {
+  return median_pt_per_unit_something(range,true);
+}
+
+
+//----------------------------------------------------------------------
+/// the median of (pt/area) for jets contained within range, counting
+/// the empty area as if it were made up of a collection of empty
+/// jets each of area (0.55 * pi R^2).
+double ClusterSequenceAreaBase::median_pt_per_unit_something(
+                const RangeDefinition & range, bool use_area_4vector) const {
+
+  double median, sigma, mean_area;
+  get_median_rho_and_sigma(range, use_area_4vector, median, sigma, mean_area);
+  return median;
+
+}
+
+
+//----------------------------------------------------------------------
+/// fits a form pt_per_unit_area(y) = a + b*y^2 for jets in range. 
+/// exclude_above allows one to exclude large values of pt/area from fit. 
+/// use_area_4vector = true uses the 4vector areas.
+void ClusterSequenceAreaBase::parabolic_pt_per_unit_area(
+       double & a, double & b, const RangeDefinition & range, 
+       double exclude_above, bool use_area_4vector) const {
+  
+  int n=0;
+  int n_excluded = 0;
+  double mean_f=0, mean_x2=0, mean_x4=0, mean_fx2=0; 
+
+  vector<PseudoJet> incl_jets = inclusive_jets();
+
+  for (unsigned i = 0; i < incl_jets.size(); i++) {
+    if (range.is_in_range(incl_jets[i])) {
+      double this_area;
+      if ( use_area_4vector ) {
+          this_area = area_4vector(incl_jets[i]).perp();     
+      } else {
+          this_area = area(incl_jets[i]);
+      }
+      double f = incl_jets[i].perp()/this_area;
+      if (exclude_above <= 0.0 || f < exclude_above) {
+	double x = incl_jets[i].rap(); double x2 = x*x;
+	mean_f   += f;
+	mean_x2  += x2;
+	mean_x4  += x2*x2;
+	mean_fx2 += f*x2;
+	n++;
+      } else {
+	n_excluded++;
+      }
+    }
+  }
+
+  if (n <= 1) {
+    // meaningful results require at least two jets inside the
+    // area -- mind you if there are empty jets we should be in 
+    // any case doing something special...
+    a = 0.0;
+    b = 0.0;
+  } else {
+    mean_f   /= n;
+    mean_x2  /= n;
+    mean_x4  /= n;
+    mean_fx2 /= n;
+    
+    b = (mean_f*mean_x2 - mean_fx2)/(mean_x2*mean_x2 - mean_x4);
+    a = mean_f - b*mean_x2;
+  }
+  //cerr << "n_excluded = "<< n_excluded << endl;
+}
+
+
+
+
+void ClusterSequenceAreaBase::get_median_rho_and_sigma(
+            const RangeDefinition & range, bool use_area_4vector,
+            double & median, double & sigma, double & mean_area) const {
+
+  _check_jet_alg_good_for_median();
+
+  vector<double> pt_over_areas;
+  vector<PseudoJet> incl_jets = inclusive_jets();
+  double total_area  = 0.0;
+  double total_njets = 0;
+
+  for (unsigned i = 0; i < incl_jets.size(); i++) {
+    if (range.is_in_range(incl_jets[i])) {
+      double this_area;
+      if (use_area_4vector) {
+          this_area = area_4vector(incl_jets[i]).perp();
+      } else {
+          this_area = area(incl_jets[i]);
+      }
+      pt_over_areas.push_back(incl_jets[i].perp()/this_area);
+      total_area  += this_area;
+      total_njets += 1.0;
+    }
+  }
+
+  // there is nothing inside our region, so answer will always be zero
+  if (pt_over_areas.size() == 0) {
+    median = 0.0;
+    sigma  = 0.0;
+    mean_area = 0.0;
+    return;
+  }
+  
+  // get median (pt/area) [this is the "old" median definition. It considers
+  // only the "real" jets in calculating the median, i.e. excluding the
+  // only-ghost ones]
+  sort(pt_over_areas.begin(), pt_over_areas.end());
+
+  // now get the median & error, accounting for empty jets
+  // define the fractions of distribution at median, median-1sigma
+  double posn[2] = {0.5, (1.0-0.6827)/2.0};
+  double res[2];
+  
+  double n_empty = n_empty_jets(range);
+  total_njets += n_empty;
+  total_area  += empty_area(range);
+
+  for (int i = 0; i < 2; i++) {
+    double nj_median_pos = 
+      (pt_over_areas.size()-1 + n_empty)*posn[i] - n_empty;
+    double nj_median_ratio;
+    if (nj_median_pos >= 0 && pt_over_areas.size() > 1) {
+      int int_nj_median = int(nj_median_pos);
+      nj_median_ratio = 
+        pt_over_areas[int_nj_median] * (int_nj_median+1-nj_median_pos)
+        + pt_over_areas[int_nj_median+1] * (nj_median_pos - int_nj_median);
+    } else {
+      nj_median_ratio = 0.0;
+    }
+    res[i] = nj_median_ratio;
+  }
+  median = res[0];
+  double error  = res[0] - res[1];
+  mean_area = total_area / total_njets;
+  sigma  = error * sqrt(mean_area);
+}
+
+
+/// return a vector of all subtracted jets, using area_4vector, given rho.
+/// Only inclusive_jets above ptmin are subtracted and returned.
+/// the ordering is the same as that of sorted_by_pt(cs.inclusive_jets()),
+/// i.e. not necessarily ordered in pt once subtracted
+vector<PseudoJet> ClusterSequenceAreaBase::subtracted_jets(const double rho,
+                                                           const double ptmin) 
+                                                           const {
+  vector<PseudoJet> sub_jets;
+  vector<PseudoJet> jets = sorted_by_pt(inclusive_jets(ptmin));
+  for (unsigned i=0; i<jets.size(); i++) {
+     PseudoJet sub_jet = subtracted_jet(jets[i],rho);
+     sub_jets.push_back(sub_jet);
+  }
+  return sub_jets;
+}
+
+/// return a vector of subtracted jets, using area_4vector.
+/// Only inclusive_jets above ptmin are subtracted and returned.
+/// the ordering is the same as that of sorted_by_pt(cs.inclusive_jets()),
+/// i.e. not necessarily ordered in pt once subtracted
+vector<PseudoJet> ClusterSequenceAreaBase::subtracted_jets(
+                                                 const RangeDefinition & range, 
+						 const double ptmin)
+						 const {
+  double rho = median_pt_per_unit_area_4vector(range);
+  return subtracted_jets(rho,ptmin);
+}
+
+
+/// return a subtracted jet, using area_4vector, given rho
+PseudoJet ClusterSequenceAreaBase::subtracted_jet(const PseudoJet & jet,
+                                                  const double rho) const {
+  PseudoJet area4vect = area_4vector(jet);
+  PseudoJet sub_jet;
+  // sanity check
+  if (rho*area4vect.perp() < jet.perp() ) { 
+    sub_jet = jet - rho*area4vect;
+  } else { sub_jet = PseudoJet(0.0,0.0,0.0,0.0); }
+  
+  // make sure the subtracted jet has the same index 
+  // (i.e. "looks like") the original jet
+  sub_jet.set_cluster_hist_index(jet.cluster_hist_index());
+  
+  return sub_jet;
+}
+
+
+/// return a subtracted jet, using area_4vector;  note that this is
+/// potentially inefficient if repeatedly used for many different
+/// jets, because rho will be recalculated each time around.
+PseudoJet ClusterSequenceAreaBase::subtracted_jet(const PseudoJet & jet,
+                                       const RangeDefinition & range) const {
+  double rho = median_pt_per_unit_area_4vector(range);
+  PseudoJet sub_jet = subtracted_jet(jet, rho);
+  return sub_jet;
+}
+
+
+/// return the subtracted pt, given rho
+double ClusterSequenceAreaBase::subtracted_pt(const PseudoJet & jet,
+                                              const double rho,
+                                              bool use_area_4vector) const {
+  if ( use_area_4vector ) { 
+     PseudoJet sub_jet = subtracted_jet(jet,rho);
+     return sub_jet.perp();
+  } else {
+     return jet.perp() - rho*area(jet);
+  }
+}  
+
+
+/// return the subtracted pt; note that this is
+/// potentially inefficient if repeatedly used for many different
+/// jets, because rho will be recalculated each time around.
+double ClusterSequenceAreaBase::subtracted_pt(const PseudoJet & jet,
+                                              const RangeDefinition & range,
+                                              bool use_area_4vector) const {
+  if ( use_area_4vector ) { 
+     PseudoJet sub_jet = subtracted_jet(jet,range);
+     return sub_jet.perp();
+  } else {
+     double rho = median_pt_per_unit_area(range);
+     return subtracted_pt(jet,rho,false);
+  }
+}  
+
+
+/// check the jet algorithm is suitable (and if not issue a warning)
+void ClusterSequenceAreaBase::_check_jet_alg_good_for_median() const {
+  if (jet_def().jet_algorithm() != kt_algorithm
+      && jet_def().jet_algorithm() != cambridge_algorithm
+      && jet_def().jet_algorithm() !=  cambridge_for_passive_algorithm) {
+    _warnings.warn("ClusterSequenceAreaBase: jet_def being used may not be suitable for estimating diffuse backgrounds (good options are kt, cam)");
+  }
+}
+
+
+
+FASTJET_END_NAMESPACE
Index: /trunk/Utilities/Fastjet/src/ClusterSequencePassiveArea.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequencePassiveArea.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequencePassiveArea.cc	(revision 11)
@@ -0,0 +1,108 @@
+//STARTHEADER
+// $Id: ClusterSequencePassiveArea.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/ClusterSequencePassiveArea.hh"
+#include "../include/fastjet/ClusterSequenceVoronoiArea.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+using namespace std;
+
+//----------------------------------------------------------------------
+/// global routine for initialising and running a passive area that is
+/// correct in general, but that chooses an optimal approach for
+/// various special cases.
+void ClusterSequencePassiveArea::_initialise_and_run_PA (
+		const JetDefinition & jet_def,
+		const GhostedAreaSpec & area_spec,
+		const bool & writeout_combinations) {
+
+  if (jet_def.jet_algorithm() == kt_algorithm) {
+    // first run the passive area
+    ClusterSequenceVoronoiArea csva(_jets,jet_def,VoronoiAreaSpec(1.0));
+    // now set up and transfer relevant information    
+    // first the clustering sequence
+    transfer_from_sequence(csva);
+    // then the areas
+    _resize_and_zero_AA();
+    for (unsigned i = 0; i < _history.size(); i++) {
+      int ijetp = _history[i].jetp_index;
+      if (ijetp != Invalid) {
+        _average_area[i] = csva.area(_jets[ijetp]);
+        _average_area_4vector[i] = csva.area_4vector(_jets[ijetp]);
+      }
+    }
+
+  } else if (jet_def.jet_algorithm() == cambridge_algorithm) {
+    // run a variant of the cambridge algorithm that has been hacked
+    // to deal with passive areas
+    JetDefinition tmp_jet_def = jet_def;
+    tmp_jet_def.set_jet_finder(cambridge_for_passive_algorithm);
+    tmp_jet_def.set_extra_param(sqrt(area_spec.mean_ghost_kt()));
+    _initialise_and_run_AA(tmp_jet_def, area_spec, writeout_combinations);
+    _jet_def = jet_def;
+
+  } else if (jet_def.jet_algorithm() == antikt_algorithm) {
+    // for the antikt algorithm, passive and active are identical
+    _initialise_and_run_AA(jet_def, area_spec, writeout_combinations);
+
+  } else if (jet_def.jet_algorithm() == plugin_algorithm &&
+             jet_def.plugin()->supports_ghosted_passive_areas()) {
+    // for some plugin algorithms, one can "prime" the algorithm with information
+    // about the ghost scale, and then an "AA" run will actually give a passive
+    // area
+    double ghost_sep_scale_store = jet_def.plugin()->ghost_separation_scale();
+    jet_def.plugin()->set_ghost_separation_scale(sqrt(area_spec.mean_ghost_kt()));
+    _initialise_and_run_AA(jet_def, area_spec, writeout_combinations);
+
+    // restore the original ghost_sep_scale
+    jet_def.plugin()->set_ghost_separation_scale(ghost_sep_scale_store);
+
+  } else {
+    // for a generic algorithm, just run the 1GhostPassiveArea
+    _initialise_and_run_1GPA(jet_def, area_spec, writeout_combinations);
+  }
+}
+
+//----------------------------------------------------------------------
+// dispatch to most relevant empty area calculation...
+double ClusterSequencePassiveArea::empty_area (const RangeDefinition & range) const {
+  if (jet_def().jet_algorithm() == kt_algorithm) {
+    // run the naive algorithm
+    return ClusterSequenceAreaBase::empty_area(range);
+  } else {
+    return ClusterSequence1GhostPassiveArea::empty_area(range);
+  }
+}
+
+
+FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequenceVoronoiArea.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequenceVoronoiArea.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequenceVoronoiArea.cc	(revision 11)
@@ -0,0 +1,315 @@
+//STARTHEADER
+// $Id: ClusterSequenceVoronoiArea.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2006-2007 Matteo Cacciari, Gavin Salam and Gregory Soyez
+//
+//----------------------------------------------------------------------
+// This file is part of a simple command-line handling environment
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/ClusterSequenceVoronoiArea.hh"
+#include "../include/fastjet/internal/Voronoi.hh"
+#include <list>
+#include <cassert>
+#include <ostream>
+#include <fstream>
+#include <iterator>
+#include <cmath>
+#include <limits>
+
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+typedef ClusterSequenceVoronoiArea::VoronoiAreaCalc VAC;
+
+/// class for carrying out a voronoi area calculation on a set of
+/// initial vectors
+class ClusterSequenceVoronoiArea::VoronoiAreaCalc {
+public:
+  /// constructor that takes a range of a vector together with the
+  /// effective radius for the intersection of discs with voronoi
+  /// cells
+  VoronoiAreaCalc(const vector<PseudoJet>::const_iterator &,
+		  const vector<PseudoJet>::const_iterator &,
+		  double effective_R);
+
+  /// return the area of the particle associated with the given
+  /// index
+  inline double area (int index) const {return _areas[index];};
+
+private:
+  std::vector<double> _areas;     ///< areas, numbered as jets
+  double _effective_R;            ///< effective radius
+  double _effective_R_squared;    ///< effective radius squared
+
+  /**
+   * compute the intersection of one triangle with the circle
+   * the area is returned
+   */
+  double edge_circle_intersection(const Point &p0,
+				  const GraphEdge &edge);
+
+  /// get the area of a circle of radius R centred on the point 0 with
+  /// 1 and 2 on each "side" of the arc. dij is the distance between
+  /// point i and point j and all distances are squared
+  inline double circle_area(const double d12_2, double d01_2, double d02_2){
+    return 0.5*_effective_R_squared
+      *acos((d01_2+d02_2-d12_2)/(2*sqrt(d01_2*d02_2)));
+  }
+};
+
+
+/**
+ * compute the intersection of one triangle with the circle
+ * the area is returned
+ */
+double VAC::edge_circle_intersection(const Point &p0,
+				     const GraphEdge &edge){
+  Point p1(edge.x1-p0.x, edge.y1-p0.y);
+  Point p2(edge.x2-p0.x, edge.y2-p0.y);
+  Point pdiff = p2-p1;
+  
+  //fprintf(stdout, "\tpt(%f,%f)\n", p0.x, p0.y);
+
+  double cross = vector_product(p1, p2);
+  double d12_2 = norm(pdiff);
+  double d01_2 = norm(p1);
+  double d02_2 = norm(p2);
+  
+  // compute intersections between edge line and circle
+  double delta = d12_2*_effective_R_squared - cross*cross;
+  
+  // if no intersection, area=area_circle
+  if (delta<=0){
+    return circle_area(d12_2, d01_2, d02_2);
+  }
+
+  // we'll only need delta's sqrt now
+  delta = sqrt(delta);
+
+  // b is the projection of 01 onto 12
+  double b = scalar_product(pdiff, p1);
+
+  // intersections with the circle:
+  //   we compute the "coordinate along the line" of the intersection
+  //   with t=0 (1) corresponding to p1 (p2)
+  // points with 0<t<1 are within the circle others are outside
+
+  // positive intersection
+  double tp = (delta-b)/d12_2;
+
+  // if tp is negative, tm also => inters = circle
+  if (tp<0)
+    return circle_area(d12_2, d01_2, d02_2);
+
+  // we need the second intersection
+  double tm = -(delta+b)/d12_2;
+
+  // if tp<1, it lies in the circle
+  if (tp<1){
+    // if tm<0, the segment has one intersection
+    // with the circle at p (t=tp)
+    // the area is a triangle from 1 to p
+    //        then a circle   from p to 2
+    // several tricks can be used:
+    //  - the area of the triangle is tp*area triangle
+    //  - the lenght for the circle are easily obtained
+    if (tm<0)
+      return tp*0.5*fabs(cross)
+        +circle_area((1-tp)*(1-tp)*d12_2, _effective_R_squared, d02_2);
+
+    // now, 0 < tm < tp < 1
+    // the segment intersects twice the circle
+    //   area = 2 cirles at ends + a triangle in the middle
+    // again, simplifications are staightforward
+    return (tp-tm)*0.5*fabs(cross)
+      + circle_area(tm*tm*d12_2, d01_2, _effective_R_squared)
+      + circle_area((1-tp)*(1-tp)*d12_2, _effective_R_squared, d02_2);
+  }
+
+  // now, we have tp>1
+
+  // if in addition tm>1, intersectino is a circle
+  if (tm>1)
+    return circle_area(d12_2, d01_2, d02_2);
+
+  // if tm<0, the triangle is inside the circle
+  if (tm<0)
+    return 0.5*fabs(cross);
+
+  // otherwise, only the "tm point" is on the segment
+  //   area = circle from 1 to m and triangle from m to 2
+
+  return (1-tm)*0.5*fabs(cross)
+    +circle_area(tm*tm*d12_2, d01_2, _effective_R_squared);
+}
+
+
+// the constructor...
+//----------------------------------------------------------------------
+VAC::VoronoiAreaCalc(const vector<PseudoJet>::const_iterator &jet_begin,
+		     const vector<PseudoJet>::const_iterator &jet_end,
+		     double effective_R) {
+
+  assert(effective_R < 0.5*pi);
+
+  vector<Point> voronoi_particles;
+  vector<int> voronoi_indices;
+
+  _effective_R         = effective_R;
+  _effective_R_squared = effective_R*effective_R;
+
+  double minrap = numeric_limits<double>::max();
+  double maxrap = -minrap;
+
+  unsigned int n_tot = 0, n_added = 0;
+
+  // loop over jets and create the triangulation, as well as cross-referencing
+  // info
+  for (vector<PseudoJet>::const_iterator jet_it = jet_begin; 
+       jet_it != jet_end; jet_it++) {
+    _areas.push_back(0.0);
+    if ((jet_it->perp2()) != 0.0 || (jet_it->E() != jet_it->pz())){
+      // generate the corresponding point
+      double rap = jet_it->rap(), phi = jet_it->phi();
+      voronoi_particles.push_back(Point(rap, phi));
+      voronoi_indices.push_back(n_tot);
+      n_added++;
+
+      // insert a copy of the point if it falls within 2*_R_effective
+      // of the 0,2pi borders (because we are interested in any
+      // voronoi edge within _R_effective of the other border)
+      if (phi < 2*_effective_R) {
+	voronoi_particles.push_back(Point(rap,phi+twopi));
+	voronoi_indices.push_back(-1);
+	n_added++;
+      } else if (twopi-phi < 2*_effective_R) {
+	voronoi_particles.push_back(Point(rap,phi-twopi));
+	voronoi_indices.push_back(-1);
+	n_added++;
+      }
+
+      // track the rapidity range
+      maxrap = max(maxrap,rap);
+      minrap = min(minrap,rap);
+    }
+    n_tot++;
+  }
+
+  assert(n_added > 0);
+
+  // add extreme cases (corner particles):
+  double max_extend = 2*max(maxrap-minrap+4*_effective_R, twopi+8*_effective_R);
+  voronoi_particles.push_back(Point(0.5*(minrap+maxrap)-max_extend, pi));
+  voronoi_particles.push_back(Point(0.5*(minrap+maxrap)+max_extend, pi));
+  voronoi_particles.push_back(Point(0.5*(minrap+maxrap), pi-max_extend));
+  voronoi_particles.push_back(Point(0.5*(minrap+maxrap), pi+max_extend));
+
+  // Build the VD
+  VoronoiDiagramGenerator vdg;
+  vdg.generateVoronoi(&voronoi_particles, 
+		      0.5*(minrap+maxrap)-max_extend, 0.5*(minrap+maxrap)+max_extend,
+		      pi-max_extend, pi+max_extend);
+
+  vdg.resetIterator();
+  GraphEdge *e=NULL;
+  unsigned int v_index;
+  int p_index;
+  vector<PseudoJet>::const_iterator jet;
+
+  while(vdg.getNext(&e)){
+    v_index = e->point1;
+    if (v_index<n_added){ // this removes the corner particles
+      p_index = voronoi_indices[v_index];
+      if (p_index!=-1){   // this removes the copies
+	jet = jet_begin+voronoi_indices[v_index];
+	_areas[p_index]+=
+	  edge_circle_intersection(voronoi_particles[v_index], *e);
+      }
+    }
+    v_index = e->point2;
+    if (v_index<n_added){ // this removes the corner particles
+      p_index = voronoi_indices[v_index];
+      if (p_index!=-1){   // this removes the copies
+	jet = jet_begin+voronoi_indices[v_index];
+	_areas[p_index]+=
+	  edge_circle_intersection(voronoi_particles[v_index], *e);
+      }
+    }
+  }
+
+
+}
+
+
+//----------------------------------------------------------------------
+///
+void ClusterSequenceVoronoiArea::_initializeVA () {
+  // run the VAC on our original particles
+  _pa_calc = new VAC(_jets.begin(), 
+		     _jets.begin()+n_particles(),
+		     _effective_Rfact*_jet_def.R());
+
+  // transfer the areas to our local structure
+  //  -- first the initial ones
+  _voronoi_area.reserve(2*n_particles());
+  for (unsigned int i=0; i<n_particles(); i++) {
+    _voronoi_area.push_back(_pa_calc->area(i));
+    // make a stab at a 4-vector area
+    if (_jets[i].perp2() > 0) {
+      _voronoi_area_4vector.push_back((_pa_calc->area(i)/_jets[i].perp())
+                                      * _jets[i]);
+    } else {
+      // not sure what to do here -- just put zero (it won't be meaningful
+      // anyway)
+      _voronoi_area_4vector.push_back(PseudoJet(0.0,0.0,0.0,0.0));
+    }
+  }
+	   
+  //  -- then the combined areas that arise from the clustering
+  for (unsigned int i = n_particles(); i < _history.size(); i++) {
+    double area;
+    PseudoJet area_4vect;
+    if (_history[i].parent2 >= 0) {
+      area = _voronoi_area[_history[i].parent1] + 
+  	     _voronoi_area[_history[i].parent2];
+      area_4vect = _voronoi_area_4vector[_history[i].parent1] + 
+                   _voronoi_area_4vector[_history[i].parent2];
+    } else {
+      area = _voronoi_area[_history[i].parent1];
+      area_4vect = _voronoi_area_4vector[_history[i].parent1];
+    }
+    _voronoi_area.push_back(area);
+    _voronoi_area_4vector.push_back(area_4vect);
+  }
+
+}
+
+//----------------------------------------------------------------------
+ClusterSequenceVoronoiArea::~ClusterSequenceVoronoiArea() {
+  delete _pa_calc;
+}
+
+FASTJET_END_NAMESPACE
Index: /trunk/Utilities/Fastjet/src/ClusterSequence_CP2DChan.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence_CP2DChan.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence_CP2DChan.cc	(revision 11)
@@ -0,0 +1,346 @@
+//STARTHEADER
+// $Id: ClusterSequence_CP2DChan.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/ClusterSequence.hh"
+#include "../include/fastjet/internal/ClosestPair2D.hh"
+#include<limits>
+#include<vector>
+#include<cmath>
+#include<iostream>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+// place for things we don't want outside world to run into
+namespace Private {
+  /// class for helping us deal with mirror-image particles.
+  class MirrorInfo{
+  public:
+    int orig, mirror;
+    MirrorInfo(int a, int b) : orig(a), mirror(b) {};
+    MirrorInfo() {};
+  };
+
+  /// if there is a need for a mirror when looking for closest pairs
+  /// up to distance D, then return true and turn the supplied point
+  /// into its mirror copy
+  bool make_mirror(Coord2D & point, double Dlim) {
+    if (point.y < Dlim)       {point.y += twopi; return true;}
+    if (twopi-point.y < Dlim) {point.y -= twopi; return true;}
+    return false;
+  }
+  
+}
+
+using namespace Private;
+
+
+//----------------------------------------------------------------------
+/// clusters only up to a distance Dlim -- does not deal with "inclusive" jets
+/// -- these are left to some other part of the program
+void ClusterSequence::_CP2DChan_limited_cluster (double Dlim) {
+  
+  unsigned int n = _initial_n;
+
+  vector<MirrorInfo>   coordIDs(2*n); // coord IDs of a given jetID
+  vector<int>          jetIDs(2*n);   // jet ID for a given coord ID
+  vector<Coord2D>      coords(2*n);   // our coordinates (and copies)
+
+  // start things off...
+  double minrap = numeric_limits<double>::max();
+  double maxrap = -minrap;
+  int coord_index = -1;
+  int n_active = 0;
+  for (unsigned jet_i = 0; jet_i < _jets.size(); jet_i++) {
+
+    // skip jets that already have children or that have infinite
+    // rapidity
+    if (_history[_jets[jet_i].cluster_hist_index()].child != Invalid ||
+	(_jets[jet_i].E() == abs(_jets[jet_i].pz()) && 
+	 _jets[jet_i].perp2() == 0.0)
+	) {continue;}
+
+    n_active++;
+
+    coordIDs[jet_i].orig = ++coord_index;
+    coords[coord_index]  = Coord2D(_jets[jet_i].rap(), _jets[jet_i].phi_02pi());
+    jetIDs[coord_index]  = jet_i;
+    minrap = min(coords[coord_index].x,minrap);
+    maxrap = max(coords[coord_index].x,maxrap);
+
+    Coord2D mirror_point(coords[coord_index]);
+    if (make_mirror(mirror_point, Dlim)) {
+      coordIDs[jet_i].mirror = ++coord_index;
+      coords[coord_index] = mirror_point;
+      jetIDs[coord_index] = jet_i;
+    } else {
+      coordIDs[jet_i].mirror = Invalid;
+    }
+  }
+
+  // set them to their actual size...
+  coords.resize(coord_index+1);
+
+  // establish limits (with some leeway on rapidity)
+  Coord2D left_edge(minrap-1.0, -pi);
+  Coord2D right_edge(maxrap+1.0, 3*pi);
+
+  //cerr << "minrap, maxrap = " << minrap << " " << maxrap << endl;
+
+  // now create the closest pair search object
+  ClosestPair2D cp(coords, left_edge, right_edge);
+
+  // cross check to see what's going on...
+  //cerr << "Tree depths before: ";
+  //cp.print_tree_depths(cerr);
+
+  // and start iterating...
+  vector<Coord2D> new_points(2);
+  vector<unsigned int> cIDs_to_remove(4);
+  vector<unsigned int> new_cIDs(2);
+
+  do {
+    // find out which pair we recombine
+    unsigned int cID1, cID2;
+    double distance2;
+    cp.closest_pair(cID1,cID2,distance2);
+
+    // if the closest distance > Dlim, we exit and go to "inclusive" stage
+    if (distance2 > Dlim*Dlim) {break;}
+
+    // normalise distance as we like it
+    distance2 *= _invR2;
+
+    // do the recombination...
+    int jet_i = jetIDs[cID1];
+    int jet_j = jetIDs[cID2];
+    int newjet_k;
+    _do_ij_recombination_step(jet_i, jet_j, distance2, newjet_k);
+
+    // don't bother with any further action if only one active particle
+    // is left (also avoid closest-pair error [cannot remove last particle]).
+    if (--n_active == 1) {break;}
+
+    // now prepare operations on CP structure
+    cIDs_to_remove.resize(0);
+    cIDs_to_remove.push_back(coordIDs[jet_i].orig);
+    cIDs_to_remove.push_back(coordIDs[jet_j].orig);
+    if (coordIDs[jet_i].mirror != Invalid) 
+      cIDs_to_remove.push_back(coordIDs[jet_i].mirror);
+    if (coordIDs[jet_j].mirror != Invalid) 
+      cIDs_to_remove.push_back(coordIDs[jet_j].mirror);
+
+    Coord2D new_point(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi());
+    new_points.resize(0);
+    new_points.push_back(new_point);
+    if (make_mirror(new_point, Dlim)) new_points.push_back(new_point);
+    
+    // carry out actions on search tree
+    cp.replace_many(cIDs_to_remove, new_points, new_cIDs);
+
+    // now fill in info for new points...
+    coordIDs[newjet_k].orig = new_cIDs[0];
+    jetIDs[new_cIDs[0]]       = newjet_k;
+    if (new_cIDs.size() == 2) {
+      coordIDs[newjet_k].mirror = new_cIDs[1];
+      jetIDs[new_cIDs[1]]         = newjet_k;
+    } else {coordIDs[newjet_k].mirror = Invalid;}
+    
+    //// if we've reached one "active" jet we should exit...
+    //n_active--;
+    //if (n_active == 1) {break;}
+
+  } while(true);
+  
+  // cross check to see what's going on...
+  //cerr << "Max tree depths after: ";
+  //cp.print_tree_depths(cerr);
+
+}
+
+
+//----------------------------------------------------------------------
+/// a variant of the closest pair clustering which uses a region of
+/// size 2pi+2R in phi.
+void ClusterSequence::_CP2DChan_cluster_2pi2R () {
+
+  if (_jet_algorithm != cambridge_algorithm) throw Error("CP2DChan clustering method called for a jet-finder that is not the cambridge algorithm");
+
+  // run the clustering with mirror copies kept such that only things
+  // within _Rparam of a border are mirrored
+  _CP2DChan_limited_cluster(_Rparam);
+
+  //
+  _do_Cambridge_inclusive_jets();
+}
+
+
+//----------------------------------------------------------------------
+/// a variant of the closest pair clustering which uses a region of
+/// size 2pi + 2*0.3 and then carries on with 2pi+2*R
+void ClusterSequence::_CP2DChan_cluster_2piMultD () {
+
+  // do a first run of clustering up to a small distance parameter,
+  if (_Rparam >= 0.39) {
+    _CP2DChan_limited_cluster(min(_Rparam/2,0.3));
+  }
+
+  // and then the final round of clustering
+  _CP2DChan_cluster_2pi2R ();
+}
+
+
+//----------------------------------------------------------------------
+/// a 4pi variant of the closest pair clustering
+void ClusterSequence::_CP2DChan_cluster () {
+
+  if (_jet_algorithm != cambridge_algorithm) throw Error("_CP2DChan_cluster called for a jet-finder that is not the cambridge algorithm");
+
+  unsigned int n = _jets.size();
+
+  vector<MirrorInfo>   coordIDs(2*n);  // link from original to mirror indices
+  vector<int>          jetIDs(2*n);     // link from mirror to original indices
+  vector<Coord2D>      coords(2*n);   // our coordinates (and copies)
+
+  // start things off...
+  double minrap = numeric_limits<double>::max();
+  double maxrap = -minrap;
+  int coord_index = 0;
+  for (unsigned i = 0; i < n; i++) {
+    // separate out points with infinite rapidity
+    if (_jets[i].E() == abs(_jets[i].pz()) && _jets[i].perp2() == 0.0) {
+      coordIDs[i] = MirrorInfo(BeamJet,BeamJet);
+    } else {
+      coordIDs[i].orig   = coord_index;
+      coordIDs[i].mirror = coord_index+1;
+      coords[coord_index]   = Coord2D(_jets[i].rap(), _jets[i].phi_02pi());
+      coords[coord_index+1] = Coord2D(_jets[i].rap(), _jets[i].phi_02pi()+twopi);
+      jetIDs[coord_index]   = i;
+      jetIDs[coord_index+1] = i;
+      minrap = min(coords[coord_index].x,minrap);
+      maxrap = max(coords[coord_index].x,maxrap);
+      coord_index += 2;
+    }
+  }
+  // label remaining "mirror info" as saying that there are no jets
+  for (unsigned i = n; i < 2*n; i++) {coordIDs[i].orig = Invalid;}
+
+  // set them to their actual size...
+  coords.resize(coord_index);
+
+  // establish limits (with some leeway on rapidity)
+  Coord2D left_edge(minrap-1.0, 0.0);
+  Coord2D right_edge(maxrap+1.0, 2*twopi);
+
+  // now create the closest pair search object
+  ClosestPair2D cp(coords, left_edge, right_edge);
+
+  // and start iterating...
+  vector<Coord2D> new_points(2);
+  vector<unsigned int> cIDs_to_remove(4);
+  vector<unsigned int> new_cIDs(2);
+  do {
+    // find out which pair we recombine
+    unsigned int cID1, cID2;
+    double distance2;
+    cp.closest_pair(cID1,cID2,distance2);
+    distance2 *= _invR2;
+
+    // if the closest distance > 1, we exit and go to "inclusive" stage
+    if (distance2 > 1.0) {break;}
+
+    // do the recombination...
+    int jet_i = jetIDs[cID1];
+    int jet_j = jetIDs[cID2];
+    int newjet_k;
+    _do_ij_recombination_step(jet_i, jet_j, distance2, newjet_k);
+
+    // now prepare operations on CP structure
+    cIDs_to_remove[0] = coordIDs[jet_i].orig;
+    cIDs_to_remove[1] = coordIDs[jet_i].mirror;
+    cIDs_to_remove[2] = coordIDs[jet_j].orig;
+    cIDs_to_remove[3] = coordIDs[jet_j].mirror;
+    new_points[0] = Coord2D(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi());
+    new_points[1] = Coord2D(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi()+twopi);
+    // carry out the CP operation
+    //cp.replace_many(cIDs_to_remove, new_points, new_cIDs);
+    // remarkable the following is faster...
+    new_cIDs[0] = cp.replace(cIDs_to_remove[0], cIDs_to_remove[2], new_points[0]);
+    new_cIDs[1] = cp.replace(cIDs_to_remove[1], cIDs_to_remove[3], new_points[1]);
+    // signal that the following jets no longer exist
+    coordIDs[jet_i].orig = Invalid;
+    coordIDs[jet_j].orig = Invalid;
+    // and do bookkeeping for new jet
+    coordIDs[newjet_k] = MirrorInfo(new_cIDs[0], new_cIDs[1]);
+    jetIDs[new_cIDs[0]] = newjet_k;
+    jetIDs[new_cIDs[1]] = newjet_k;
+
+    // if we've reached one jet we should exit...
+    n--;
+    if (n == 1) {break;}
+
+  } while(true);
+  
+
+  // now do "beam" recombinations 
+  //for (unsigned int jet_i = 0; jet_i < coordIDs.size(); jet_i++) {
+  //  // if we have a predeclared beam jet or a valid set of mirror
+  //  // coordinates, recombine then recombine this jet with the beam
+  //  if (coordIDs[jet_i].orig == BeamJet || coordIDs[jet_i].orig > 0) {
+  //    // diB = 1 _always_ (for the cambridge alg.)
+  //    _do_iB_recombination_step(jet_i, 1.0);
+  //  }
+  //}
+
+  _do_Cambridge_inclusive_jets();
+
+  //n = _history.size();
+  //for (unsigned int hist_i = 0; hist_i < n; hist_i++) {
+  //  if (_history[hist_i].child == Invalid) {
+  //    _do_iB_recombination_step(_history[hist_i].jetp_index, 1.0);
+  //  }
+  //}
+
+}
+
+
+//----------------------------------------------------------------------
+void ClusterSequence::_do_Cambridge_inclusive_jets () {
+  unsigned int n = _history.size();
+  for (unsigned int hist_i = 0; hist_i < n; hist_i++) {
+    if (_history[hist_i].child == Invalid) {
+      _do_iB_recombination_step(_history[hist_i].jetp_index, 1.0);
+    }
+  }
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequence_Delaunay.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence_Delaunay.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence_Delaunay.cc	(revision 11)
@@ -0,0 +1,256 @@
+//STARTHEADER
+// $Id: ClusterSequence_Delaunay.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#include "../include/fastjet/Error.hh"
+#include "../include/fastjet/PseudoJet.hh"
+#include "../include/fastjet/ClusterSequence.hh"
+#include<iostream>
+#include<sstream>
+#include<cmath>
+#include <cstdlib>
+#include<cassert>
+//
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#include "fastjet/internal/Dnn4piCylinder.hh"
+#include "fastjet/internal/Dnn3piCylinder.hh"
+#include "fastjet/internal/Dnn2piCylinder.hh"
+#endif //  DROP_CGAL 
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+
+//----------------------------------------------------------------------
+/// Run the clustering using a Hierarchical Delaunay triangulation and
+/// STL maps to achieve O(N*ln N) behaviour.
+///
+/// There may be internally asserted assumptions about absence of
+/// points with coincident eta-phi coordinates.
+void ClusterSequence::_delaunay_cluster () {
+
+  int n = _jets.size();
+
+  vector<EtaPhi> points(n); // recall EtaPhi is just a typedef'd pair<double>
+  for (int i = 0; i < n; i++) {
+    points[i] = EtaPhi(_jets[i].rap(),_jets[i].phi_02pi());
+    points[i].sanitize(); // make sure things are in the right range
+  }
+
+  // initialise our DNN structure with the set of points
+  DynamicNearestNeighbours * DNN;
+#ifndef DROP_CGAL // strategy = NlnN* are not supported if we drop CGAL...
+  bool verbose = false;
+  bool ignore_nearest_is_mirror = (_Rparam < twopi);
+  if (_strategy == NlnN4pi) {
+    DNN = new Dnn4piCylinder(points,verbose);
+  } else if (_strategy == NlnN3pi) {
+    DNN = new Dnn3piCylinder(points,ignore_nearest_is_mirror,verbose);
+  } else if (_strategy == NlnN) {
+    DNN = new Dnn2piCylinder(points,ignore_nearest_is_mirror,verbose);
+  } else 
+#else
+  if (_strategy == NlnN4pi || _strategy == NlnN3pi || _strategy == NlnN) {
+    ostringstream err;
+    err << "ERROR: Requested strategy "<<strategy_string()<<" but it is not"<<endl;
+    err << "       supported because FastJet was compiled without CGAL"<<endl;
+    throw Error(err.str());
+    //assert(false);
+  }
+#endif // DROP_CGAL
+  {
+    ostringstream err;
+    err << "ERROR: Unrecognized value for strategy: "<<_strategy<<endl;
+    assert(false);
+    throw Error(err.str());
+  }
+
+  // We will find nearest neighbour for each vertex, and include
+  // distance in map (NB DistMap is a typedef given in the .h file)
+  DistMap DijMap;
+
+  // fill the map with the minimal (as far as we know) subset of Dij
+  // distances (i.e. nearest neighbour ones).
+  for (int ii = 0; ii < n; ii++) {
+    _add_ktdistance_to_map(ii, DijMap, DNN);
+  }
+
+  // run the clustering (go up to i=n-1, but then will stop half-way down,
+  // when we reach that point -- it will be the final beam jet and there
+  // will be no nearest neighbours to find).
+  for (int i=0;i<n;i++) {
+    // find nearest vertices
+    // NB: skip cases where the point is not there anymore!
+    TwoVertices SmallestDijPair;
+    int jet_i, jet_j;
+    double SmallestDij;
+    bool Valid2;
+    bool recombine_with_beam;
+    do { 
+      SmallestDij = DijMap.begin()->first;
+      SmallestDijPair = DijMap.begin()->second;
+      jet_i = SmallestDijPair.first;
+      jet_j = SmallestDijPair.second;
+      // distance is immediately removed regardless of whether or not
+      // it is used.
+      // Some temporary testing code relating to problems with the gcc-3.2 compiler
+      //cout << "got here and size is "<< DijMap.size()<< " and it is "<<SmallestDij <<"\n";
+      //cout <<  jet_i << " "<< jet_j<<"\n";
+      DijMap.erase(DijMap.begin());
+      //cout << "got beyond here\n";
+
+      // need to "prime" the validity of jet_j in such a way that 
+      // if it corresponds to the beam then it is automatically valid.
+      recombine_with_beam = (jet_j == BeamJet);
+      if (!recombine_with_beam) {Valid2 = DNN->Valid(jet_j);} 
+      else {Valid2 = true;}
+
+    } while ( !DNN->Valid(jet_i) || !Valid2);
+
+
+    // The following part acts just on jet momenta and on the history.
+    // The action on the nearest-neighbour structures takes place
+    // later (only if at least 2 jets are around).
+    if (! recombine_with_beam) {
+      int nn; // will be index of new jet
+      _do_ij_recombination_step(jet_i, jet_j, SmallestDij, nn);
+      //OBS // merge the two jets, add new jet, remove old ones
+      //OBS _jets.push_back(_jets[jet_i] + _jets[jet_j]);
+      //OBS 
+      //OBS int nn = _jets.size()-1;
+      //OBS _jets[nn].set_cluster_hist_index(n+i);
+      //OBS 
+      //OBS // get corresponding indices in history structure
+      //OBS int hist_i = _jets[jet_i].cluster_hist_index();
+      //OBS int hist_j = _jets[jet_j].cluster_hist_index();
+      //OBS 
+      //OBS 
+      //OBS _add_step_to_history(n+i,min(hist_i,hist_j), max(hist_i,hist_j),
+      //OBS 		      _jets.size()-1, SmallestDij);
+
+      // add new point to points vector
+      EtaPhi newpoint(_jets[nn].rap(), _jets[nn].phi_02pi());
+      newpoint.sanitize(); // make sure it is in correct range
+      points.push_back(newpoint);
+    } else {
+      // recombine the jet with the beam
+      _do_iB_recombination_step(jet_i, SmallestDij);
+      //OBS _add_step_to_history(n+i,_jets[jet_i].cluster_hist_index(),BeamJet,
+      //OBS 			   Invalid, SmallestDij);
+    }
+
+    // exit the loop because we do not want to look for nearest neighbours
+    // etc. of zero partons
+    if (i == n-1) {break;}
+
+    vector<int> updated_neighbours;
+    if (! recombine_with_beam) {
+      // update DNN
+      int point3;
+      DNN->RemoveCombinedAddCombination(jet_i, jet_j, 
+				       points[points.size()-1], point3,
+				       updated_neighbours);
+      // C++ beginners' comment: static_cast to unsigned int is necessary
+      // to do away with warnings about type mismatch between point3 (int) 
+      // and points.size (unsigned int)
+      if (static_cast<unsigned int> (point3) != points.size()-1) {
+	throw Error("INTERNAL ERROR: point3 != points.size()-1");}
+    } else {
+      // update DNN
+      DNN->RemovePoint(jet_i, updated_neighbours);
+    }
+
+    // update map
+    vector<int>::iterator it = updated_neighbours.begin();
+    for (; it != updated_neighbours.end(); ++it) {
+      int ii = *it;
+      _add_ktdistance_to_map(ii, DijMap, DNN);
+    }
+      
+  } // end clustering loop 
+  
+  // remember to clean up!
+  delete DNN;
+}
+
+
+//----------------------------------------------------------------------
+/// Add the current kt distance for particle ii to the map (DijMap)
+/// using information from the DNN object. Work as follows:
+/// 
+/// . if the kt is zero then it's nearest neighbour is taken to be the
+///   the beam jet and the distance is zero.
+///
+/// . if cylinder distance to nearest neighbour > _Rparam then it is
+///   yiB that is smallest and this is added to map.
+///
+/// . otherwise if the nearest neighbour jj has a larger kt then add
+///   dij to the map.
+///
+/// . otherwise do nothing
+///
+void ClusterSequence::_add_ktdistance_to_map(
+                          const int & ii, 
+			  DistMap & DijMap,
+			  const DynamicNearestNeighbours * DNN) {
+  
+  double yiB = jet_scale_for_algorithm(_jets[ii]);
+  if (yiB == 0.0) {
+    // in this case convention is that we do not worry about distances
+    // but directly state that nearest neighbour is beam
+    DijMap.insert(DijEntry(yiB,  TwoVertices(ii,-1)));
+  } else {
+    double DeltaR2 = DNN->NearestNeighbourDistance(ii) * _invR2;
+    // Logic of following bit is: only add point to map if it has
+    // smaller kt2 than nearest neighbour j (if it has larger kt,
+    // then: either it is j's nearest neighbour and then we will
+    // include dij when we come to j; or it is not j's nearest
+    // neighbour and j will recombine with someone else).
+    
+    // If DeltaR2 > 1.0 then in any case it will recombine with beam rather
+    // than with any neighbours.
+    // (put general normalisation here at some point)
+    if (DeltaR2 > 1.0) {
+      DijMap.insert(DijEntry(yiB,  TwoVertices(ii,-1)));
+    } else {
+      double kt2i = jet_scale_for_algorithm(_jets[ii]);
+      int jj = DNN->NearestNeighbourIndex(ii);
+      if (kt2i <= jet_scale_for_algorithm(_jets[jj])) {
+	double dij = DeltaR2 * kt2i;
+	DijMap.insert(DijEntry(dij, TwoVertices(ii,jj)));
+      }
+    }
+  }
+}
+
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequence_DumbN3.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence_DumbN3.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence_DumbN3.cc	(revision 11)
@@ -0,0 +1,135 @@
+//STARTHEADER
+// $Id: ClusterSequence_DumbN3.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#include "../include/fastjet/PseudoJet.hh"
+#include "../include/fastjet/ClusterSequence.hh"
+#include<iostream>
+#include<cmath>
+#include <cstdlib>
+#include<cassert>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+using namespace std;
+
+
+//----------------------------------------------------------------------
+/// Run the clustering in a very slow variant of the N^3 algorithm. 
+///
+/// The only thing this routine has going for it is that memory usage
+/// is O(N)!
+void ClusterSequence::_really_dumb_cluster () {
+
+  // the array that will be overwritten here will be one
+  // of pointers to jets.
+  vector<PseudoJet *> jetsp(_jets.size());
+  vector<int>         indices(_jets.size());
+
+  for (size_t i = 0; i<_jets.size(); i++) {
+    jetsp[i] = & _jets[i];
+    indices[i] = i;
+  }
+
+  for (int n = jetsp.size(); n > 0; n--) {
+    int ii, jj;
+    // find smallest beam distance [remember jet_scale_for_algorithm 
+    // will return kt^2 for the kt-algorithm and 1 for the Cambridge/Aachen]
+    double ymin = jet_scale_for_algorithm(*(jetsp[0]));
+    ii = 0; jj = -2;
+    for (int i = 0; i < n; i++) {
+      double yiB = jet_scale_for_algorithm(*(jetsp[i]));
+      if (yiB < ymin) {
+	ymin = yiB; ii = i; jj = -2;}
+    }
+
+    // find smallest distance between pair of jetsp
+    for (int i = 0; i < n-1; i++) {
+      for (int j = i+1; j < n; j++) {
+	//double y = jetsp[i]->kt_distance(*jetsp[j])*_invR2;
+	double y = min(jet_scale_for_algorithm(*(jetsp[i])), 
+		       jet_scale_for_algorithm(*(jetsp[j])))
+	            * jetsp[i]->plain_distance(*jetsp[j])*_invR2;
+	if (y < ymin) {ymin = y; ii = i; jj = j;}
+      }
+    }
+
+    // output recombination sequence
+    // old "ktclus" way of labelling
+    //cout <<n<< " "<< ii+1 << " with " << jj+1 << "; y = "<< ymin<<endl;
+    // new delaunay way of labelling
+    int jjindex_or_beam, iiindex;
+    if (jj < 0) {jjindex_or_beam = BeamJet; iiindex = indices[ii];} 
+    else {
+      jjindex_or_beam = max(indices[ii],indices[jj]);
+      iiindex =         min(indices[ii],indices[jj]);
+    }
+
+    // now recombine
+    int newn = 2*jetsp.size() - n;
+    if (jj >= 0) {
+      // combine pair
+      int nn; // new jet index
+      _do_ij_recombination_step(jetsp[ii]-&_jets[0], 
+				jetsp[jj]-&_jets[0], ymin, nn);
+      
+      // sort out internal bookkeeping
+      jetsp[ii] = &_jets[nn];
+      // have jj point to jet that was pointed at by n-1 
+      // (since original jj is no longer current, so put n-1 into jj)
+      jetsp[jj] = jetsp[n-1];
+      indices[ii] = newn;
+      indices[jj] = indices[n-1];
+
+      //OBS_jets.push_back(*jetsp[ii] + *jetsp[jj]);
+      //OBSjetsp[ii] = &_jets[_jets.size()-1];
+      //OBS// have jj point to jet that was pointed at by n-1 
+      //OBS// (since original jj is no longer current, so put n-1 into jj)
+      //OBSjetsp[jj] = jetsp[n-1];
+      //OBS
+      //OBSindices[ii] = newn;
+      //OBSindices[jj] = indices[n-1];
+      //OBS_add_step_to_history(newn,iiindex,
+      //OBS			      jjindex_or_beam,_jets.size()-1,ymin);
+    } else {
+      // combine ii with beam
+      _do_iB_recombination_step(jetsp[ii]-&_jets[0], ymin);
+      // put last jet (pointer) in place of ii (which has disappeared)
+      jetsp[ii] = jetsp[n-1];
+      indices[ii] = indices[n-1];
+      //OBS_add_step_to_history(newn,iiindex,jjindex_or_beam,Invalid, ymin);
+    }
+  }
+
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequence_N2.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence_N2.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence_N2.cc	(revision 11)
@@ -0,0 +1,182 @@
+//STARTHEADER
+// $Id: ClusterSequence_N2.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+// The plain N^2 part of the ClusterSequence class -- separated out
+// from the rest of the class implementation so as to speed up
+// compilation of this particular part while it is under test.
+
+#include "../include/fastjet/PseudoJet.hh"
+#include "../include/fastjet/ClusterSequence.hh"
+#include<iostream>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+using namespace std;
+
+//----------------------------------------------------------------------
+/// Order(N^2) clustering 
+///
+void ClusterSequence::_simple_N2_cluster() {
+  int n = _jets.size();
+  BriefJet * briefjets = new BriefJet[n];
+  BriefJet * jetA = briefjets, * jetB;
+  
+  // initialise the basic jet info 
+  for (int i = 0; i< n; i++) {
+    _bj_set_jetinfo(jetA, i);
+    jetA++; // move on to next entry of briefjets
+  }
+  BriefJet * tail = jetA; // a semaphore for the end of briefjets
+  BriefJet * head = briefjets; // a nicer way of naming start
+
+  // now initialise the NN distances: jetA will run from 1..n-1; and
+  // jetB from 0..jetA-1
+  for (jetA = head + 1; jetA != tail; jetA++) {
+    // set NN info for jetA based on jets running from head..jetA-1,
+    // checking in the process whether jetA itself is an undiscovered
+    // NN of one of those jets.
+    _bj_set_NN_crosscheck(jetA, head, jetA);
+  }
+
+
+  // now create the diJ (where J is i's NN) table -- remember that 
+  // we differ from standard normalisation here by a factor of R2
+  double * diJ = new double[n];
+  jetA = head;
+  for (int i = 0; i < n; i++) {
+    diJ[i] = _bj_diJ(jetA);
+    jetA++; // have jetA follow i
+  }
+
+  // now run the recombination loop
+  int history_location = n-1;
+  while (tail != head) {
+
+    // find the minimum of the diJ on this round
+    double diJ_min = diJ[0];
+    int diJ_min_jet = 0;
+    for (int i = 1; i < n; i++) {
+      if (diJ[i] < diJ_min) {diJ_min_jet = i; diJ_min  = diJ[i];}
+    }
+    
+    // do the recombination between A and B
+    history_location++;
+    jetA = & briefjets[diJ_min_jet];
+    jetB = jetA->NN;
+    // put the normalisation back in
+    diJ_min *= _invR2; 
+    if (jetB != NULL) {
+      // jet-jet recombination
+      // If necessary relabel A & B to ensure jetB < jetA, that way if
+      // the larger of them == newtail then that ends up being jetA and 
+      // the new jet that is added as jetB is inserted in a position that
+      // has a future!
+      if (jetA < jetB) {swap(jetA,jetB);}
+
+      int nn; // new jet index
+      _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
+
+      //OBS // get the two history indices
+      //OBS int hist_a = _jets[jetA->_jets_index].cluster_hist_index();
+      //OBS int hist_b = _jets[jetB->_jets_index].cluster_hist_index();
+      //OBS // create the recombined jet
+      //OBS _jets.push_back(_jets[jetA->_jets_index] + _jets[jetB->_jets_index]);
+      //OBS int nn = _jets.size() - 1;
+      //OBS _jets[nn].set_cluster_hist_index(history_location);
+      //OBS // update history
+      //OBS _add_step_to_history(history_location, 
+      //OBS   		   min(hist_a,hist_b),max(hist_a,hist_b),
+      //OBS 			   nn, diJ_min);
+      // what was jetB will now become the new jet
+      _bj_set_jetinfo(jetB, nn);
+    } else {
+      // jet-beam recombination
+      _do_iB_recombination_step(jetA->_jets_index, diJ_min);
+      //OBS // get the hist_index
+      //OBS int hist_a = _jets[jetA->_jets_index].cluster_hist_index();
+      //OBS _add_step_to_history(history_location,hist_a,BeamJet,Invalid,diJ_min); 
+    }
+
+    // now update our nearest neighbour info and diJ table
+    // first reduce size of table
+    tail--; n--;
+    // Copy last jet contents and diJ info into position of jetA
+    *jetA = *tail;
+    diJ[jetA - head] = diJ[tail-head];
+
+    // Initialise jetB's NN distance as well as updating it for 
+    // other particles.
+    // NB: by having different loops for jetB == or != NULL we could
+    //     perhaps save a few percent (usually avoid one if inside loop),
+    //     but will not do it for now because on laptop fluctuations are
+    //     too large to reliably measure a few percent difference...
+    for (BriefJet * jetI = head; jetI != tail; jetI++) {
+      // see if jetI had jetA or jetB as a NN -- if so recalculate the NN
+      if (jetI->NN == jetA || jetI->NN == jetB) {
+	_bj_set_NN_nocross(jetI, head, tail);
+	diJ[jetI-head] = _bj_diJ(jetI); // update diJ 
+      } 
+      // check whether new jetB is closer than jetI's current NN and
+      // if need be update things
+      if (jetB != NULL) {
+	double dist = _bj_dist(jetI,jetB);
+	if (dist < jetI->NN_dist) {
+	  if (jetI != jetB) {
+	    jetI->NN_dist = dist;
+	    jetI->NN = jetB;
+	    diJ[jetI-head] = _bj_diJ(jetI); // update diJ...
+	  }
+	}
+	if (dist < jetB->NN_dist) {
+	  if (jetI != jetB) {
+	    jetB->NN_dist = dist;
+	    jetB->NN      = jetI;}
+	}
+      }
+      // if jetI's NN is the new tail then relabel it so that it becomes jetA
+      if (jetI->NN == tail) {jetI->NN = jetA;}
+    }
+
+    
+    if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
+
+
+  }
+  
+
+  // final cleaning up;
+  delete[] diJ;
+  delete[] briefjets;
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/ClusterSequence_TiledN2.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/ClusterSequence_TiledN2.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/ClusterSequence_TiledN2.cc	(revision 11)
@@ -0,0 +1,931 @@
+//STARTHEADER
+// $Id: ClusterSequence_TiledN2.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+// The plain N^2 part of the ClusterSequence class -- separated out
+// from the rest of the class implementation so as to speed up
+// compilation of this particular part while it is under test.
+
+#include<iostream>
+#include<vector>
+#include<cmath>
+#include<algorithm>
+#include "../include/fastjet/PseudoJet.hh"
+#include "../include/fastjet/ClusterSequence.hh"
+#include "../include/fastjet/internal/MinHeap.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+
+//----------------------------------------------------------------------
+void ClusterSequence::_bj_remove_from_tiles(TiledJet * const jet) {
+  Tile * tile = & _tiles[jet->tile_index];
+
+  if (jet->previous == NULL) {
+    // we are at head of the tile, so reset it.
+    // If this was the only jet on the tile then tile->head will now be NULL
+    tile->head = jet->next;
+  } else {
+    // adjust link from previous jet in this tile
+    jet->previous->next = jet->next;
+  }
+  if (jet->next != NULL) {
+    // adjust backwards-link from next jet in this tile
+    jet->next->previous = jet->previous;
+  }
+}
+
+//----------------------------------------------------------------------
+/// Set up the tiles:
+///  - decide the range in eta
+///  - allocate the tiles
+///  - set up the cross-referencing info between tiles
+///
+/// The neighbourhood of a tile is set up as follows
+///
+/// 	      LRR
+///           LXR
+///           LLR
+///
+/// such that tiles is an array containing XLLLLRRRR with pointers
+///                                         |   \ RH_tiles
+///                                         \ surrounding_tiles
+///
+/// with appropriate precautions when close to the edge of the tiled
+/// region.
+///
+void ClusterSequence::_initialise_tiles() {
+
+  // first decide tile sizes
+  _tile_size_eta = _Rparam;
+  _n_tiles_phi   = int(floor(twopi/_Rparam));
+  _tile_size_phi = twopi / _n_tiles_phi; // >= _Rparam and fits in 2pi
+
+  // always include zero rapidity in the tiling region
+  _tiles_eta_min = 0.0;
+  _tiles_eta_max = 0.0;
+  // but go no further than following
+  const double maxrap = 7.0;
+
+  // and find out how much further one should go
+  for(unsigned int i = 0; i < _jets.size(); i++) {
+    double eta = _jets[i].rap();
+    // first check if eta is in range -- to avoid taking into account
+    // very spurious rapidities due to particles with near-zero kt.
+    if (abs(eta) < maxrap) {
+      if (eta < _tiles_eta_min) {_tiles_eta_min = eta;}
+      if (eta > _tiles_eta_max) {_tiles_eta_max = eta;}
+    }
+  }
+
+  // now adjust the values
+  _tiles_ieta_min = int(floor(_tiles_eta_min/_tile_size_eta));
+  _tiles_ieta_max = int(floor( _tiles_eta_max/_tile_size_eta));
+  _tiles_eta_min = _tiles_ieta_min * _tile_size_eta;
+  _tiles_eta_max = _tiles_ieta_max * _tile_size_eta;
+
+  // allocate the tiles
+  _tiles.resize((_tiles_ieta_max-_tiles_ieta_min+1)*_n_tiles_phi);
+
+  // now set up the cross-referencing between tiles
+  for (int ieta = _tiles_ieta_min; ieta <= _tiles_ieta_max; ieta++) {
+    for (int iphi = 0; iphi < _n_tiles_phi; iphi++) {
+      Tile * tile = & _tiles[_tile_index(ieta,iphi)];
+      // no jets in this tile yet
+      tile->head = NULL; // first element of tiles points to itself
+      tile->begin_tiles[0] =  tile;
+      Tile ** pptile = & (tile->begin_tiles[0]);
+      pptile++;
+      //
+      // set up L's in column to the left of X
+      tile->surrounding_tiles = pptile;
+      if (ieta > _tiles_ieta_min) {
+	// with the itile subroutine, we can safely run tiles from
+	// idphi=-1 to idphi=+1, because it takes care of
+	// negative and positive boundaries
+	for (int idphi = -1; idphi <=+1; idphi++) {
+	  *pptile = & _tiles[_tile_index(ieta-1,iphi+idphi)];
+	  pptile++;
+	}	
+      }
+      // now set up last L (below X)
+      *pptile = & _tiles[_tile_index(ieta,iphi-1)];
+      pptile++;
+      // set up first R (above X)
+      tile->RH_tiles = pptile;
+      *pptile = & _tiles[_tile_index(ieta,iphi+1)];
+      pptile++;
+      // set up remaining R's, to the right of X
+      if (ieta < _tiles_ieta_max) {
+	for (int idphi = -1; idphi <= +1; idphi++) {
+	  *pptile = & _tiles[_tile_index(ieta+1,iphi+idphi)];
+	  pptile++;
+	}	
+      }
+      // now put semaphore for end tile
+      tile->end_tiles = pptile;
+      // finally make sure tiles are untagged
+      tile->tagged = false;
+    }
+  }
+
+}
+
+
+//----------------------------------------------------------------------
+/// return the tile index corresponding to the given eta,phi point
+int ClusterSequence::_tile_index(const double & eta, const double & phi) const {
+  int ieta, iphi;
+  if      (eta <= _tiles_eta_min) {ieta = 0;}
+  else if (eta >= _tiles_eta_max) {ieta = _tiles_ieta_max-_tiles_ieta_min;}
+  else {
+    //ieta = int(floor((eta - _tiles_eta_min) / _tile_size_eta));
+    ieta = int(((eta - _tiles_eta_min) / _tile_size_eta));
+    // following needed in case of rare but nasty rounding errors
+    if (ieta > _tiles_ieta_max-_tiles_ieta_min) {
+      ieta = _tiles_ieta_max-_tiles_ieta_min;} 
+  }
+  // allow for some extent of being beyond range in calculation of phi
+  // as well
+  //iphi = (int(floor(phi/_tile_size_phi)) + _n_tiles_phi) % _n_tiles_phi;
+  // with just int and no floor, things run faster but beware
+  iphi = int((phi+twopi)/_tile_size_phi) % _n_tiles_phi;
+  return (iphi + ieta * _n_tiles_phi);
+}
+
+
+//----------------------------------------------------------------------
+// overloaded version which additionally sets up information regarding the
+// tiling
+inline void ClusterSequence::_tj_set_jetinfo( TiledJet * const jet,
+					      const int _jets_index) {
+  // first call the generic setup
+  _bj_set_jetinfo<>(jet, _jets_index);
+
+  // Then do the setup specific to the tiled case.
+
+  // Find out which tile it belonds to
+  jet->tile_index = _tile_index(jet->eta, jet->phi);
+
+  // Insert it into the tile's linked list of jets
+  Tile * tile = &_tiles[jet->tile_index];
+  jet->previous   = NULL;
+  jet->next       = tile->head;
+  if (jet->next != NULL) {jet->next->previous = jet;}
+  tile->head      = jet;
+}
+
+
+//----------------------------------------------------------------------
+/// output the contents of the tiles
+void ClusterSequence::_print_tiles(TiledJet * briefjets ) const {
+  for (vector<Tile>::const_iterator tile = _tiles.begin(); 
+       tile < _tiles.end(); tile++) {
+    cout << "Tile " << tile - _tiles.begin()<<" = ";
+    vector<int> list;
+    for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
+      list.push_back(jetI-briefjets);
+      //cout <<" "<<jetI-briefjets;
+    }
+    sort(list.begin(),list.end());
+    for (unsigned int i = 0; i < list.size(); i++) {cout <<" "<<list[i];}
+    cout <<"\n";
+  }
+}
+
+
+//----------------------------------------------------------------------
+/// Add to the vector tile_union the tiles that are in the neighbourhood
+/// of the specified tile_index, including itself -- start adding
+/// from position n_near_tiles-1, and increase n_near_tiles as
+/// you go along (could have done it more C++ like with vector with reserved
+/// space, but fear is that it would have been slower, e.g. checking
+/// for end of vector at each stage to decide whether to resize it)
+void ClusterSequence::_add_neighbours_to_tile_union(const int tile_index, 
+	       vector<int> & tile_union, int & n_near_tiles) const {
+  for (Tile * const * near_tile = _tiles[tile_index].begin_tiles; 
+       near_tile != _tiles[tile_index].end_tiles; near_tile++){
+    // get the tile number
+    tile_union[n_near_tiles] = *near_tile - & _tiles[0];
+    n_near_tiles++;
+  }
+}
+
+
+//----------------------------------------------------------------------
+/// Like _add_neighbours_to_tile_union, but only adds neighbours if 
+/// their "tagged" status is false; when a neighbour is added its
+/// tagged status is set to true.
+inline void ClusterSequence::_add_untagged_neighbours_to_tile_union(
+               const int tile_index, 
+	       vector<int> & tile_union, int & n_near_tiles)  {
+  for (Tile ** near_tile = _tiles[tile_index].begin_tiles; 
+       near_tile != _tiles[tile_index].end_tiles; near_tile++){
+    if (! (*near_tile)->tagged) {
+      (*near_tile)->tagged = true;
+      // get the tile number
+      tile_union[n_near_tiles] = *near_tile - & _tiles[0];
+      n_near_tiles++;
+    }
+  }
+}
+
+
+//----------------------------------------------------------------------
+/// run a tiled clustering
+void ClusterSequence::_tiled_N2_cluster() {
+
+  _initialise_tiles();
+
+  int n = _jets.size();
+  TiledJet * briefjets = new TiledJet[n];
+  TiledJet * jetA = briefjets, * jetB;
+  TiledJet oldB;
+  
+
+  // will be used quite deep inside loops, but declare it here so that
+  // memory (de)allocation gets done only once
+  vector<int> tile_union(3*n_tile_neighbours);
+  
+  // initialise the basic jet info 
+  for (int i = 0; i< n; i++) {
+    _tj_set_jetinfo(jetA, i);
+    //cout << i<<": "<<jetA->tile_index<<"\n";
+    jetA++; // move on to next entry of briefjets
+  }
+  TiledJet * tail = jetA; // a semaphore for the end of briefjets
+  TiledJet * head = briefjets; // a nicer way of naming start
+
+  // set up the initial nearest neighbour information
+  vector<Tile>::const_iterator tile;
+  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
+    // first do it on this tile
+    for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
+      for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
+	double dist = _bj_dist(jetA,jetB);
+	if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
+	if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
+      }
+    }
+    // then do it for RH tiles
+    for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
+      for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
+	for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
+	  double dist = _bj_dist(jetA,jetB);
+	  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
+	  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
+	}
+      }
+    }
+  }
+  
+  // now create the diJ (where J is i's NN) table -- remember that 
+  // we differ from standard normalisation here by a factor of R2
+  double * diJ = new double[n];
+  jetA = head;
+  for (int i = 0; i < n; i++) {
+    diJ[i] = _bj_diJ(jetA);
+    jetA++; // have jetA follow i
+  }
+
+  // now run the recombination loop
+  int history_location = n-1;
+  while (tail != head) {
+
+    // find the minimum of the diJ on this round
+    double diJ_min = diJ[0];
+    int diJ_min_jet = 0;
+    for (int i = 1; i < n; i++) {
+      if (diJ[i] < diJ_min) {diJ_min_jet = i; diJ_min  = diJ[i];}
+    }
+
+    // do the recombination between A and B
+    history_location++;
+    jetA = & briefjets[diJ_min_jet];
+    jetB = jetA->NN;
+    // put the normalisation back in
+    diJ_min *= _invR2; 
+
+    //if (n == 19) {cout << "Hello "<<jetA-head<<" "<<jetB-head<<"\n";}
+
+    //cout <<" WILL RECOMBINE "<< jetA-briefjets<<" "<<jetB-briefjets<<"\n";
+
+    if (jetB != NULL) {
+      // jet-jet recombination
+      // If necessary relabel A & B to ensure jetB < jetA, that way if
+      // the larger of them == newtail then that ends up being jetA and 
+      // the new jet that is added as jetB is inserted in a position that
+      // has a future!
+      if (jetA < jetB) {swap(jetA,jetB);}
+
+      int nn; // new jet index
+      _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
+
+      //OBS// get the two history indices
+      //OBSint hist_a = _jets[jetA->_jets_index].cluster_hist_index();
+      //OBSint hist_b = _jets[jetB->_jets_index].cluster_hist_index();
+      //OBS// create the recombined jet
+      //OBS_jets.push_back(_jets[jetA->_jets_index] + _jets[jetB->_jets_index]);
+      //OBSint nn = _jets.size() - 1;
+      //OBS_jets[nn].set_cluster_hist_index(history_location);
+      //OBS// update history
+      //OBS//cout <<n-1<<" "<<jetA-head<<" "<<jetB-head<<"; ";
+      //OBS_add_step_to_history(history_location, 
+      //OBS  		   min(hist_a,hist_b),max(hist_a,hist_b),
+      //OBS			   nn, diJ_min);
+
+      // what was jetB will now become the new jet
+      _bj_remove_from_tiles(jetA);
+      oldB = * jetB;  // take a copy because we will need it...
+      _bj_remove_from_tiles(jetB);
+      _tj_set_jetinfo(jetB, nn); // also registers the jet in the tiling
+    } else {
+      // jet-beam recombination
+      _do_iB_recombination_step(jetA->_jets_index, diJ_min);
+	    
+      //OBS// get the hist_index
+      //OBSint hist_a = _jets[jetA->_jets_index].cluster_hist_index();
+      //OBS//cout <<n-1<<" "<<jetA-head<<" "<<-1<<"; ";
+      //OBS_add_step_to_history(history_location,hist_a,BeamJet,Invalid,diJ_min); 
+      _bj_remove_from_tiles(jetA);
+    }
+
+    // first establish the set of tiles over which we are going to 
+    // have to run searches for updated and new nearest-neighbours
+    int n_near_tiles = 0;
+    _add_neighbours_to_tile_union(jetA->tile_index, tile_union, n_near_tiles);
+    if (jetB != NULL) {
+      bool sort_it = false;
+      if (jetB->tile_index != jetA->tile_index) {
+	sort_it = true;
+	_add_neighbours_to_tile_union(jetB->tile_index,tile_union,n_near_tiles);
+      }
+      if (oldB.tile_index != jetA->tile_index && 
+	  oldB.tile_index != jetB->tile_index) {
+	sort_it = true;
+	_add_neighbours_to_tile_union(oldB.tile_index,tile_union,n_near_tiles);
+      }
+
+      if (sort_it) {
+	// sort the tiles before then compressing the list
+	sort(tile_union.begin(), tile_union.begin()+n_near_tiles);
+	// and now condense the list
+	int nnn = 1;
+	for (int i = 1; i < n_near_tiles; i++) {
+	  if (tile_union[i] != tile_union[nnn-1]) {
+	    tile_union[nnn] = tile_union[i]; 
+	    nnn++;
+	  }
+	}
+	n_near_tiles = nnn;
+      }
+    }
+
+    // now update our nearest neighbour info and diJ table
+    // first reduce size of table
+    tail--; n--;
+    if (jetA == tail) {
+      // there is nothing to be done
+    } else {
+      // Copy last jet contents and diJ info into position of jetA
+      *jetA = *tail;
+      diJ[jetA - head] = diJ[tail-head];
+      // IN the tiling fix pointers to tail and turn them into
+      // pointers to jetA (from predecessors, successors and the tile
+      // head if need be)
+      if (jetA->previous == NULL) {
+	_tiles[jetA->tile_index].head = jetA;
+      } else {
+	jetA->previous->next = jetA;
+      }
+      if (jetA->next != NULL) {jetA->next->previous = jetA;}
+    }
+
+    // Initialise jetB's NN distance as well as updating it for 
+    // other particles.
+    for (int itile = 0; itile < n_near_tiles; itile++) {
+      Tile * tile = &_tiles[tile_union[itile]];
+      for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
+	// see if jetI had jetA or jetB as a NN -- if so recalculate the NN
+	if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
+	  jetI->NN_dist = _R2;
+	  jetI->NN      = NULL;
+	  // now go over tiles that are neighbours of I (include own tile)
+	  for (Tile ** near_tile  = tile->begin_tiles; 
+	               near_tile != tile->end_tiles; near_tile++) {
+	    // and then over the contents of that tile
+	    for (TiledJet * jetJ  = (*near_tile)->head; 
+                            jetJ != NULL; jetJ = jetJ->next) {
+	      double dist = _bj_dist(jetI,jetJ);
+	      if (dist < jetI->NN_dist && jetJ != jetI) {
+		jetI->NN_dist = dist; jetI->NN = jetJ;
+	      }
+	    }
+	  }
+	  diJ[jetI-head] = _bj_diJ(jetI); // update diJ 
+	}
+	// check whether new jetB is closer than jetI's current NN and
+	// if need to update things
+	if (jetB != NULL) {
+	  double dist = _bj_dist(jetI,jetB);
+	  if (dist < jetI->NN_dist) {
+	    if (jetI != jetB) {
+	      jetI->NN_dist = dist;
+	      jetI->NN = jetB;
+	      diJ[jetI-head] = _bj_diJ(jetI); // update diJ...
+	    }
+	  }
+	  if (dist < jetB->NN_dist) {
+	    if (jetI != jetB) {
+	      jetB->NN_dist = dist;
+	      jetB->NN      = jetI;}
+	  }
+	}
+      }
+    }
+
+
+    if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
+    //cout << n<<" "<<briefjets[95].NN-briefjets<<" "<<briefjets[95].NN_dist <<"\n";
+
+    // remember to update pointers to tail
+    for (Tile ** near_tile = _tiles[tail->tile_index].begin_tiles; 
+	         near_tile!= _tiles[tail->tile_index].end_tiles; near_tile++){
+      // and then the contents of that tile
+      for (TiledJet * jetJ = (*near_tile)->head; 
+	             jetJ != NULL; jetJ = jetJ->next) {
+	if (jetJ->NN == tail) {jetJ->NN = jetA;}
+      }
+    }
+
+    //for (int i = 0; i < n; i++) {
+    //  if (briefjets[i].NN-briefjets >= n && briefjets[i].NN != NULL) {cout <<"YOU MUST BE CRAZY for n ="<<n<<", i = "<<i<<", NN = "<<briefjets[i].NN-briefjets<<"\n";}
+    //}
+
+
+    if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
+    //cout << briefjets[95].NN-briefjets<<" "<<briefjets[95].NN_dist <<"\n";
+
+  }
+
+  // final cleaning up;
+  delete[] diJ;
+  delete[] briefjets;
+}
+
+
+//----------------------------------------------------------------------
+/// run a tiled clustering
+void ClusterSequence::_faster_tiled_N2_cluster() {
+
+  _initialise_tiles();
+
+  int n = _jets.size();
+  TiledJet * briefjets = new TiledJet[n];
+  TiledJet * jetA = briefjets, * jetB;
+  TiledJet oldB;
+  
+
+  // will be used quite deep inside loops, but declare it here so that
+  // memory (de)allocation gets done only once
+  vector<int> tile_union(3*n_tile_neighbours);
+  
+  // initialise the basic jet info 
+  for (int i = 0; i< n; i++) {
+    _tj_set_jetinfo(jetA, i);
+    //cout << i<<": "<<jetA->tile_index<<"\n";
+    jetA++; // move on to next entry of briefjets
+  }
+  TiledJet * head = briefjets; // a nicer way of naming start
+
+  // set up the initial nearest neighbour information
+  vector<Tile>::const_iterator tile;
+  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
+    // first do it on this tile
+    for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
+      for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
+	double dist = _bj_dist(jetA,jetB);
+	if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
+	if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
+      }
+    }
+    // then do it for RH tiles
+    for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
+      for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
+	for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
+	  double dist = _bj_dist(jetA,jetB);
+	  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
+	  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
+	}
+      }
+    }
+    // no need to do it for LH tiles, since they are implicitly done
+    // when we set NN for both jetA and jetB on the RH tiles.
+  }
+
+  
+  // now create the diJ (where J is i's NN) table -- remember that 
+  // we differ from standard normalisation here by a factor of R2
+  // (corrected for at the end). 
+  struct diJ_plus_link {
+    double     diJ; // the distance
+    TiledJet * jet; // the jet (i) for which we've found this distance
+                    // (whose NN will the J).
+  };
+  diJ_plus_link * diJ = new diJ_plus_link[n];
+  jetA = head;
+  for (int i = 0; i < n; i++) {
+    diJ[i].diJ = _bj_diJ(jetA); // kt distance * R^2
+    diJ[i].jet = jetA;  // our compact diJ table will not be in	     
+    jetA->diJ_posn = i; // one-to-one corresp. with non-compact jets,
+                        // so set up bi-directional correspondence here.
+    jetA++; // have jetA follow i 
+  }
+
+  // now run the recombination loop
+  int history_location = n-1;
+  while (n > 0) {
+
+    // find the minimum of the diJ on this round
+    diJ_plus_link * best, *stop; // pointers a bit faster than indices
+    // could use best to keep track of diJ min, but it turns out to be
+    // marginally faster to have a separate variable (avoids n
+    // dereferences at the expense of n/2 assignments).
+    double diJ_min = diJ[0].diJ; // initialise the best one here.
+    best = diJ;                  // and here
+    stop = diJ+n;
+    for (diJ_plus_link * here = diJ+1; here != stop; here++) {
+      if (here->diJ < diJ_min) {best = here; diJ_min  = here->diJ;}
+    }
+
+    // do the recombination between A and B
+    history_location++;
+    jetA = best->jet;
+    jetB = jetA->NN;
+    // put the normalisation back in
+    diJ_min *= _invR2; 
+
+    if (jetB != NULL) {
+      // jet-jet recombination
+      // If necessary relabel A & B to ensure jetB < jetA, that way if
+      // the larger of them == newtail then that ends up being jetA and 
+      // the new jet that is added as jetB is inserted in a position that
+      // has a future!
+      if (jetA < jetB) {swap(jetA,jetB);}
+
+      int nn; // new jet index
+      _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
+      
+      //OBS// get the two history indices
+      //OBSint ihstry_a = _jets[jetA->_jets_index].cluster_hist_index();
+      //OBSint ihstry_b = _jets[jetB->_jets_index].cluster_hist_index();
+      //OBS// create the recombined jet
+      //OBS_jets.push_back(_jets[jetA->_jets_index] + _jets[jetB->_jets_index]);
+      //OBSint nn = _jets.size() - 1;
+      //OBS_jets[nn].set_cluster_hist_index(history_location);
+      //OBS// update history
+      //OBS//cout <<n-1<<" "<<jetA-head<<" "<<jetB-head<<"; ";
+      //OBS_add_step_to_history(history_location, 
+      //OBS  		   min(ihstry_a,ihstry_b),max(ihstry_a,ihstry_b),
+      //OBS			   nn, diJ_min);
+      // what was jetB will now become the new jet
+      _bj_remove_from_tiles(jetA);
+      oldB = * jetB;  // take a copy because we will need it...
+      _bj_remove_from_tiles(jetB);
+      _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
+                                 // (also registers the jet in the tiling)
+    } else {
+      // jet-beam recombination
+      // get the hist_index
+      _do_iB_recombination_step(jetA->_jets_index, diJ_min);
+      //OBSint ihstry_a = _jets[jetA->_jets_index].cluster_hist_index();
+      //OBS//cout <<n-1<<" "<<jetA-head<<" "<<-1<<"; ";
+      //OBS_add_step_to_history(history_location,ihstry_a,BeamJet,Invalid,diJ_min); 
+      _bj_remove_from_tiles(jetA);
+    }
+
+    // first establish the set of tiles over which we are going to
+    // have to run searches for updated and new nearest-neighbours --
+    // basically a combination of vicinity of the tiles of the two old
+    // and one new jet.
+    int n_near_tiles = 0;
+    _add_untagged_neighbours_to_tile_union(jetA->tile_index, 
+					   tile_union, n_near_tiles);
+    if (jetB != NULL) {
+      if (jetB->tile_index != jetA->tile_index) {
+	_add_untagged_neighbours_to_tile_union(jetB->tile_index,
+					       tile_union,n_near_tiles);
+      }
+      if (oldB.tile_index != jetA->tile_index && 
+	  oldB.tile_index != jetB->tile_index) {
+	_add_untagged_neighbours_to_tile_union(oldB.tile_index,
+					       tile_union,n_near_tiles);
+      }
+    }
+
+    // now update our nearest neighbour info and diJ table
+    // first reduce size of table
+    n--;
+    // then compactify the diJ by taking the last of the diJ and copying
+    // it to the position occupied by the diJ for jetA
+    diJ[n].jet->diJ_posn = jetA->diJ_posn;
+    diJ[jetA->diJ_posn] = diJ[n];
+
+    // Initialise jetB's NN distance as well as updating it for 
+    // other particles.
+    // Run over all tiles in our union 
+    for (int itile = 0; itile < n_near_tiles; itile++) {
+      Tile * tile = &_tiles[tile_union[itile]];
+      tile->tagged = false; // reset tag, since we're done with unions
+      // run over all jets in the current tile
+      for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
+	// see if jetI had jetA or jetB as a NN -- if so recalculate the NN
+	if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
+	  jetI->NN_dist = _R2;
+	  jetI->NN      = NULL;
+	  // now go over tiles that are neighbours of I (include own tile)
+	  for (Tile ** near_tile  = tile->begin_tiles; 
+	               near_tile != tile->end_tiles; near_tile++) {
+	    // and then over the contents of that tile
+	    for (TiledJet * jetJ  = (*near_tile)->head; 
+                            jetJ != NULL; jetJ = jetJ->next) {
+	      double dist = _bj_dist(jetI,jetJ);
+	      if (dist < jetI->NN_dist && jetJ != jetI) {
+		jetI->NN_dist = dist; jetI->NN = jetJ;
+	      }
+	    }
+	  }
+	  diJ[jetI->diJ_posn].diJ = _bj_diJ(jetI); // update diJ kt-dist
+	}
+	// check whether new jetB is closer than jetI's current NN and
+	// if jetI is closer than jetB's current (evolving) nearest
+	// neighbour. Where relevant update things
+	if (jetB != NULL) {
+	  double dist = _bj_dist(jetI,jetB);
+	  if (dist < jetI->NN_dist) {
+	    if (jetI != jetB) {
+	      jetI->NN_dist = dist;
+	      jetI->NN = jetB;
+	      diJ[jetI->diJ_posn].diJ = _bj_diJ(jetI); // update diJ...
+	    }
+	  }
+	  if (dist < jetB->NN_dist) {
+	    if (jetI != jetB) {
+	      jetB->NN_dist = dist;
+	      jetB->NN      = jetI;}
+	  }
+	}
+      }
+    }
+
+    // finally, register the updated kt distance for B
+    if (jetB != NULL) {diJ[jetB->diJ_posn].diJ = _bj_diJ(jetB);}
+
+  }
+
+  // final cleaning up;
+  delete[] diJ;
+  delete[] briefjets;
+}
+
+
+
+//----------------------------------------------------------------------
+/// run a tiled clustering, with our minheap for keeping track of the
+/// smallest dij
+void ClusterSequence::_minheap_faster_tiled_N2_cluster() {
+
+  _initialise_tiles();
+
+  int n = _jets.size();
+  TiledJet * briefjets = new TiledJet[n];
+  TiledJet * jetA = briefjets, * jetB;
+  TiledJet oldB;
+  
+
+  // will be used quite deep inside loops, but declare it here so that
+  // memory (de)allocation gets done only once
+  vector<int> tile_union(3*n_tile_neighbours);
+  
+  // initialise the basic jet info 
+  for (int i = 0; i< n; i++) {
+    _tj_set_jetinfo(jetA, i);
+    //cout << i<<": "<<jetA->tile_index<<"\n";
+    jetA++; // move on to next entry of briefjets
+  }
+  TiledJet * head = briefjets; // a nicer way of naming start
+
+  // set up the initial nearest neighbour information
+  vector<Tile>::const_iterator tile;
+  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
+    // first do it on this tile
+    for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
+      for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
+	double dist = _bj_dist(jetA,jetB);
+	if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
+	if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
+      }
+    }
+    // then do it for RH tiles
+    for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
+      for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
+	for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
+	  double dist = _bj_dist(jetA,jetB);
+	  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
+	  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
+	}
+      }
+    }
+    // no need to do it for LH tiles, since they are implicitly done
+    // when we set NN for both jetA and jetB on the RH tiles.
+  }
+
+  
+  //// now create the diJ (where J is i's NN) table -- remember that 
+  //// we differ from standard normalisation here by a factor of R2
+  //// (corrected for at the end). 
+  //struct diJ_plus_link {
+  //  double     diJ; // the distance
+  //  TiledJet * jet; // the jet (i) for which we've found this distance
+  //                  // (whose NN will the J).
+  //};
+  //diJ_plus_link * diJ = new diJ_plus_link[n];
+  //jetA = head;
+  //for (int i = 0; i < n; i++) {
+  //  diJ[i].diJ = _bj_diJ(jetA); // kt distance * R^2
+  //  diJ[i].jet = jetA;  // our compact diJ table will not be in	     
+  //  jetA->diJ_posn = i; // one-to-one corresp. with non-compact jets,
+  //                      // so set up bi-directional correspondence here.
+  //  jetA++; // have jetA follow i 
+  //}
+
+  vector<double> diJs(n);
+  for (int i = 0; i < n; i++) {
+    diJs[i] = _bj_diJ(&briefjets[i]);
+    briefjets[i].label_minheap_update_done();
+  }
+  MinHeap minheap(diJs);
+  // have a stack telling us which jets we'll have to update on the heap
+  vector<TiledJet *> jets_for_minheap;
+  jets_for_minheap.reserve(n); 
+
+  // now run the recombination loop
+  int history_location = n-1;
+  while (n > 0) {
+
+    double diJ_min = minheap.minval() *_invR2;
+    jetA = head + minheap.minloc();
+
+    // do the recombination between A and B
+    history_location++;
+    jetB = jetA->NN;
+
+    if (jetB != NULL) {
+      // jet-jet recombination
+      // If necessary relabel A & B to ensure jetB < jetA, that way if
+      // the larger of them == newtail then that ends up being jetA and 
+      // the new jet that is added as jetB is inserted in a position that
+      // has a future!
+      if (jetA < jetB) {swap(jetA,jetB);}
+
+      int nn; // new jet index
+      _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
+      
+      // what was jetB will now become the new jet
+      _bj_remove_from_tiles(jetA);
+      oldB = * jetB;  // take a copy because we will need it...
+      _bj_remove_from_tiles(jetB);
+      _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
+                                 // (also registers the jet in the tiling)
+    } else {
+      // jet-beam recombination
+      // get the hist_index
+      _do_iB_recombination_step(jetA->_jets_index, diJ_min);
+      _bj_remove_from_tiles(jetA);
+    }
+
+    // remove the minheap entry for jetA
+    minheap.remove(jetA-head);
+
+    // first establish the set of tiles over which we are going to
+    // have to run searches for updated and new nearest-neighbours --
+    // basically a combination of vicinity of the tiles of the two old
+    // and one new jet.
+    int n_near_tiles = 0;
+    _add_untagged_neighbours_to_tile_union(jetA->tile_index, 
+					   tile_union, n_near_tiles);
+    if (jetB != NULL) {
+      if (jetB->tile_index != jetA->tile_index) {
+	_add_untagged_neighbours_to_tile_union(jetB->tile_index,
+					       tile_union,n_near_tiles);
+      }
+      if (oldB.tile_index != jetA->tile_index && 
+	  oldB.tile_index != jetB->tile_index) {
+	_add_untagged_neighbours_to_tile_union(oldB.tile_index,
+					       tile_union,n_near_tiles);
+      }
+      // indicate that we'll have to update jetB in the minheap
+      jetB->label_minheap_update_needed();
+      jets_for_minheap.push_back(jetB);
+    }
+
+
+    // Initialise jetB's NN distance as well as updating it for 
+    // other particles.
+    // Run over all tiles in our union 
+    for (int itile = 0; itile < n_near_tiles; itile++) {
+      Tile * tile = &_tiles[tile_union[itile]];
+      tile->tagged = false; // reset tag, since we're done with unions
+      // run over all jets in the current tile
+      for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
+	// see if jetI had jetA or jetB as a NN -- if so recalculate the NN
+	if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
+	  jetI->NN_dist = _R2;
+	  jetI->NN      = NULL;
+	  // label jetI as needing heap action...
+	  if (!jetI->minheap_update_needed()) {
+	    jetI->label_minheap_update_needed();
+	    jets_for_minheap.push_back(jetI);}
+	  // now go over tiles that are neighbours of I (include own tile)
+	  for (Tile ** near_tile  = tile->begin_tiles; 
+	               near_tile != tile->end_tiles; near_tile++) {
+	    // and then over the contents of that tile
+	    for (TiledJet * jetJ  = (*near_tile)->head; 
+                            jetJ != NULL; jetJ = jetJ->next) {
+	      double dist = _bj_dist(jetI,jetJ);
+	      if (dist < jetI->NN_dist && jetJ != jetI) {
+		jetI->NN_dist = dist; jetI->NN = jetJ;
+	      }
+	    }
+	  }
+	}
+	// check whether new jetB is closer than jetI's current NN and
+	// if jetI is closer than jetB's current (evolving) nearest
+	// neighbour. Where relevant update things
+	if (jetB != NULL) {
+	  double dist = _bj_dist(jetI,jetB);
+	  if (dist < jetI->NN_dist) {
+	    if (jetI != jetB) {
+	      jetI->NN_dist = dist;
+	      jetI->NN = jetB;
+	      // label jetI as needing heap action...
+	      if (!jetI->minheap_update_needed()) {
+		jetI->label_minheap_update_needed();
+		jets_for_minheap.push_back(jetI);}
+	    }
+	  }
+	  if (dist < jetB->NN_dist) {
+	    if (jetI != jetB) {
+	      jetB->NN_dist = dist;
+	      jetB->NN      = jetI;}
+	  }
+	}
+      }
+    }
+
+    // deal with jets whose minheap entry needs updating
+    while (jets_for_minheap.size() > 0) {
+      TiledJet * jetI = jets_for_minheap.back(); 
+      jets_for_minheap.pop_back();
+      minheap.update(jetI-head, _bj_diJ(jetI));
+      jetI->label_minheap_update_done();
+    }
+    n--;
+  }
+
+  // final cleaning up;
+  delete[] briefjets;
+}
+
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/Dnn2piCylinder.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/Dnn2piCylinder.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/Dnn2piCylinder.cc	(revision 11)
@@ -0,0 +1,244 @@
+//STARTHEADER
+// $Id: Dnn2piCylinder.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#include <set>
+#include "fastjet/internal/Dnn2piCylinder.hh"
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+/// initialiser...
+Dnn2piCylinder::Dnn2piCylinder(
+	const vector<EtaPhi> & input_points, 
+	const bool & ignore_nearest_is_mirror,
+	const bool & verbose) {
+  
+  _verbose = verbose;
+  _ignore_nearest_is_mirror = ignore_nearest_is_mirror;
+  vector<EtaPhi> plane_points;
+  vector<int>    plane_point_indices(input_points.size());
+  //plane_points.reserve(2*input_points.size());
+
+  for (unsigned int i=0; i < input_points.size(); i++) {
+    _RegisterCylinderPoint(input_points[i], plane_points);
+    plane_point_indices[i] = i;
+  }
+  
+  if (_verbose) cout << "============== Preparing _DNN" << endl;
+  _DNN = new DnnPlane(plane_points, verbose);
+
+
+  vector<int> updated_point_indices; // we'll not use information from this
+  _CreateNecessaryMirrorPoints(plane_point_indices,updated_point_indices);
+}
+
+
+//----------------------------------------------------------------------
+/// Actions here are similar to those in the
+/// Dnn3piCylinder::_RegisterCylinderPoint case, however here we do
+/// NOT create the mirror point -- instead we initialise the structure
+/// as if there were no need for the mirror point.
+///
+/// ADDITIONALLY push the cylinder_point onto the vector plane_points.
+void Dnn2piCylinder::_RegisterCylinderPoint (const EtaPhi & cylinder_point,
+					     vector<EtaPhi> & plane_points) {
+  double phi = cylinder_point.second;
+  assert(phi >= 0.0 && phi < 2*pi);
+  
+  // do main point
+  MirrorVertexInfo mvi;
+  mvi.main_index = _cylinder_index_of_plane_vertex.size();
+  _cylinder_index_of_plane_vertex.push_back(_mirror_info.size());
+  plane_points.push_back(cylinder_point);
+  mvi.mirror_index = INEXISTENT_VERTEX;
+  
+  // 
+  _mirror_info.push_back(mvi);
+}
+
+
+
+//----------------------------------------------------------------------
+/// For each plane point specified in the vector plane_indices,
+/// establish whether there is a need to create a mirror point
+/// according to the following criteria:
+///
+/// . phi < pi
+/// . mirror does not already exist
+/// . phi < NearestNeighbourDistance 
+///   (if this is not true then there is no way that its mirror point
+///   could have a nearer neighbour).
+///
+/// If conditions all hold, then create the mirror point, insert it
+/// into the _DNN structure, adjusting any nearest neighbours, and
+/// return the list of plane points whose nearest neighbours have
+/// changed (this will include the new neighbours that have just been
+/// added)
+void Dnn2piCylinder::_CreateNecessaryMirrorPoints(
+			  const vector<int> & plane_indices,
+			  vector<int> & updated_plane_points) {
+
+  vector<EtaPhi> new_plane_points;
+
+  for (size_t i = 0; i < plane_indices.size(); i++) {
+
+    int ip = plane_indices[i]; // plane index
+    EtaPhi position = _DNN->etaphi(ip);
+    double phi = position.second;
+
+    //BAD // require phi < pi
+    //BAD if (phi >= pi) {continue;}
+
+    // require absence of mirror
+    int ic = _cylinder_index_of_plane_vertex[ip];
+    if (_mirror_info[ic].mirror_index != INEXISTENT_VERTEX) {continue;}
+
+    //printf("%3d %3d %10.5f %10.5f %3d\n",ic, ip, phi, 
+    //	   _DNN->NearestNeighbourDistance(ip),_DNN->NearestNeighbourIndex(ip));
+
+
+    // check that we are sufficiently close to the border --
+    // i.e. closer than nearest neighbour distance. But RECALL:
+    // nearest neighbourDistance actually returns a squared distance
+    // (this was really stupid on our part -- caused considerable loss
+    // of time ... )
+    double nndist = _DNN->NearestNeighbourDistance(ip); 
+    if (phi*phi >= nndist && (twopi-phi)*(twopi-phi) >= nndist) {continue;}
+
+    // now proceed to prepare the point for addition
+    new_plane_points.push_back(_remap_phi(position));
+    _mirror_info[ic].mirror_index = _cylinder_index_of_plane_vertex.size();
+    _cylinder_index_of_plane_vertex.push_back(ic);
+  }
+
+  vector<int> indices_to_remove; // empty
+  vector<int> indices_added;     // will be filled as result of call
+  _DNN->RemoveAndAddPoints(indices_to_remove,new_plane_points,indices_added, 
+			   updated_plane_points);
+
+  // occasionally, addition of points might cause a change in the
+  // nearest neighbour of a point in the 0--pi range? (But should be
+  // impossible -- we add points beyond 2pi, so they can only be
+  // nearest neighbours of points in the range pi--2pi; there is one
+  // exception -- the nearest neighbour of one's self -- but in that
+  // case this will already have been discovered, so there should be
+  // nothing left to do). 
+
+  // To be on the safe side, check to see if we have updated points
+  // with phi<pi and no current mirror point. BUT: this check, as
+  // written, only makes sense when the mirror image was created only
+  // beyond 2pi, which is no longer the case. Only apparent
+  // alternative is to run separate insertions for beyond 2pi and
+  // below phi=0, with separate checks in the two cases. But, given
+  // that across a large number of recombinations and events in the
+  // old method (single mirror), we never ran into this problem, it's
+  // probably safe to assume that the arguments given above are OK! So
+  // comment out the check...
+  //NOTNEEDED for (size_t i = 0; i < updated_plane_points.size(); i++) {
+  //NOTNEEDED   int ip = updated_plane_points[i];
+  //NOTNEEDED   double phi  = _DNN->phi(ip);
+  //NOTNEEDED   int ic = _cylinder_index_of_plane_vertex[ip];
+  //NOTNEEDED   assert (!(phi < pi && _mirror_info[ic].mirror_index == INEXISTENT_VERTEX));
+  //NOTNEEDED }
+  // alternative recursive code
+  //vector<int> extra_updated_plane_points;
+  //_CreateNecessaryMirrorPoints(updated_plane_points,extra_updated_plane_points)
+  //updated_plane_points.push_back(extra_updated_plane_points);
+}
+
+
+
+//----------------------------------------------------------------------
+/// insertion and removal of points
+void Dnn2piCylinder::RemoveAndAddPoints(const vector<int> & indices_to_remove,
+				const vector<EtaPhi> & points_to_add,
+				vector<int> & indices_added,
+				vector<int> & indices_of_updated_neighbours) {
+
+  // translate from "cylinder" indices of points to remove to the
+  // plane indices of points to remove, bearing in mind that sometimes
+  // there are multple plane points to remove.
+  vector<int> plane_indices_to_remove;
+  for (unsigned int i=0; i < indices_to_remove.size(); i++) {
+    MirrorVertexInfo * mvi;
+    mvi = & _mirror_info[indices_to_remove[i]];
+    plane_indices_to_remove.push_back(mvi->main_index);
+    if (mvi->mirror_index != INEXISTENT_VERTEX) {
+      plane_indices_to_remove.push_back(mvi->mirror_index);
+    }
+  }
+
+  // given "cylinder" points to add get hold of the list of
+  // plane-points to add.
+  vector<EtaPhi> plane_points_to_add;
+  indices_added.clear();
+  for (unsigned int i=0; i < points_to_add.size(); i++) {
+    indices_added.push_back(_mirror_info.size());
+    _RegisterCylinderPoint(points_to_add[i], plane_points_to_add);
+  }
+
+  // now get the hard work done (note that we need to supply the
+  // plane_indices_added vector but that we will not actually check
+  // its contents in any way -- the indices_added that is actually
+  // returned has been calculated above).
+  vector<int> updated_plane_neighbours, plane_indices_added;
+  _DNN->RemoveAndAddPoints(plane_indices_to_remove, plane_points_to_add,
+			     plane_indices_added, updated_plane_neighbours);
+
+  vector<int> extra_updated_plane_neighbours;
+  _CreateNecessaryMirrorPoints(updated_plane_neighbours,
+			       extra_updated_plane_neighbours);
+
+  // extract, from the updated_plane_neighbours, and
+  // extra_updated_plane_neighbours, the set of cylinder neighbours
+  // that have changed
+  set<int> index_set;
+  unsigned int i;
+  for (i=0; i < updated_plane_neighbours.size(); i++) {
+    index_set.insert(
+       _cylinder_index_of_plane_vertex[updated_plane_neighbours[i]]);}
+  for (i=0; i < extra_updated_plane_neighbours.size(); i++) {
+    index_set.insert(
+       _cylinder_index_of_plane_vertex[extra_updated_plane_neighbours[i]]);}
+
+  // decant the set into the vector that needs to be returned
+  indices_of_updated_neighbours.clear();
+  for (set<int>::iterator iter = index_set.begin(); 
+       iter != index_set.end(); iter++) {
+    indices_of_updated_neighbours.push_back(*iter);
+  }
+}
+
+FASTJET_END_NAMESPACE
+
+#endif //  DROP_CGAL 
Index: /trunk/Utilities/Fastjet/src/Dnn3piCylinder.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/Dnn3piCylinder.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/Dnn3piCylinder.cc	(revision 11)
@@ -0,0 +1,161 @@
+//STARTHEADER
+// $Id: Dnn3piCylinder.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#include <set>
+#include "fastjet/internal/Dnn3piCylinder.hh"
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+/// initialiser...
+Dnn3piCylinder::Dnn3piCylinder(
+	const vector<EtaPhi> & input_points, 
+	const bool & ignore_nearest_is_mirror,
+	const bool & verbose) {
+  
+  _verbose = verbose;
+  _ignore_nearest_is_mirror = ignore_nearest_is_mirror;
+  vector<EtaPhi> plane_points;
+  //plane_points.reserve(2*input_points.size());
+
+  for (unsigned int i=0; i < input_points.size(); i++) {
+    _RegisterCylinderPoint(input_points[i], plane_points);
+  }
+
+  if (_verbose) cout << "============== Preparing _DNN" << endl;
+  _DNN = new DnnPlane(plane_points, verbose);
+}
+
+
+//----------------------------------------------------------------------
+/// What on earth does this do?
+///
+/// Example: last true "cylinder" index was 15
+///          last plane index was 23
+/// 
+/// Then: _cylinder_index_of_plane_vertex.size() = 24 and 
+///       _mirror_info.size() = 16
+///
+/// IF cylinder_point's phi < pi then
+///   create:  _mirror_info[16] = (main_index = 24, mirror_index=25) 
+///            _cylinder_index_of_plane_vertex[24] = 16
+///            _cylinder_index_of_plane_vertex[25] = 16
+/// ELSE
+///   create:  _mirror_info[16] = (main_index = 24, mirror_index=INEXISTENT..) 
+///            _cylinder_index_of_plane_vertex[24] = 16
+///
+/// ADDITIONALLY push the cylinder_point (and if it exists the mirror
+/// copy) onto the vector plane_points.
+void Dnn3piCylinder::_RegisterCylinderPoint (const EtaPhi & cylinder_point,
+					     vector<EtaPhi> & plane_points) {
+  double phi = cylinder_point.second;
+  assert(phi >= 0.0 && phi < 2*pi);
+  
+  // do main point
+  MirrorVertexInfo mvi;
+  mvi.main_index = _cylinder_index_of_plane_vertex.size();
+  _cylinder_index_of_plane_vertex.push_back(_mirror_info.size());
+  plane_points.push_back(cylinder_point);
+  
+  // do mirror point if need be
+  if (phi < pi) {
+    mvi.mirror_index = _cylinder_index_of_plane_vertex.size();
+    _cylinder_index_of_plane_vertex.push_back(_mirror_info.size());
+    plane_points.push_back(_remap_phi(cylinder_point));
+  } else {
+    mvi.mirror_index = INEXISTENT_VERTEX;
+  }
+  
+  // 
+  _mirror_info.push_back(mvi);
+}
+
+
+//----------------------------------------------------------------------
+/// insertion and removal of points
+void Dnn3piCylinder::RemoveAndAddPoints(const vector<int> & indices_to_remove,
+				const vector<EtaPhi> & points_to_add,
+				vector<int> & indices_added,
+				vector<int> & indices_of_updated_neighbours) {
+
+  // translate from "cylinder" indices of points to remove to the
+  // plane indices of points to remove, bearing in mind that sometimes
+  // there are multple plane points to remove.
+  vector<int> plane_indices_to_remove;
+  for (unsigned int i=0; i < indices_to_remove.size(); i++) {
+    MirrorVertexInfo * mvi;
+    mvi = & _mirror_info[indices_to_remove[i]];
+    plane_indices_to_remove.push_back(mvi->main_index);
+    if (mvi->mirror_index != INEXISTENT_VERTEX) {
+      plane_indices_to_remove.push_back(mvi->mirror_index);
+    }
+  }
+
+  // given "cylinder" points to add get hold of the list of
+  // plane-points to add.
+  vector<EtaPhi> plane_points_to_add;
+  indices_added.clear();
+  for (unsigned int i=0; i < points_to_add.size(); i++) {
+    indices_added.push_back(_mirror_info.size());
+    _RegisterCylinderPoint(points_to_add[i], plane_points_to_add);
+  }
+
+  // now get the hard work done (note that we need to supply the
+  // plane_indices_added vector but that we will not actually check
+  // its contents in any way -- the indices_added that is actually
+  // returned has been calculated above).
+  vector<int> updated_plane_neighbours, plane_indices_added;
+  _DNN->RemoveAndAddPoints(plane_indices_to_remove, plane_points_to_add,
+			     plane_indices_added, updated_plane_neighbours);
+
+  // extract, from the updated_plane_neighbours, the set of cylinder
+  // neighbours that have changed
+  set<int> index_set;
+  unsigned int i;
+  for (i=0; i < updated_plane_neighbours.size(); i++) {
+    index_set.insert(
+       _cylinder_index_of_plane_vertex[updated_plane_neighbours[i]]);}
+
+  // decant the set into the vector that needs to be returned
+  indices_of_updated_neighbours.clear();
+  for (set<int>::iterator iter = index_set.begin(); 
+       iter != index_set.end(); iter++) {
+    indices_of_updated_neighbours.push_back(*iter);
+  }
+}
+
+
+FASTJET_END_NAMESPACE
+
+#endif //  DROP_CGAL 
+
Index: /trunk/Utilities/Fastjet/src/Dnn4piCylinder.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/Dnn4piCylinder.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/Dnn4piCylinder.cc	(revision 11)
@@ -0,0 +1,95 @@
+//STARTHEADER
+// $Id: Dnn4piCylinder.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+#include <set>
+#include "fastjet/internal/Dnn4piCylinder.hh"
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+//----------------------------------------------------------------------
+/// initialiser...
+Dnn4piCylinder::Dnn4piCylinder(
+	const vector<EtaPhi> & input_points, const bool & verbose) {
+  
+  _verbose = verbose;
+  vector<EtaPhi> copied_points(input_points.size());
+  for (unsigned int i=0; i < input_points.size(); i++) {
+    double phi = input_points[i].second;
+    assert(phi >= 0.0 && phi < 2*pi);
+    copied_points[i] = _remap_phi(input_points[i]);
+  }
+
+  if (_verbose) cout << "============== Preparing _DNN1" << endl;
+  _DNN1 = new DnnPlane(input_points, verbose);
+  if (_verbose) cout << "============== Preparing _DNN2" << endl;
+  _DNN2 = new DnnPlane(copied_points, verbose);
+}
+
+
+//----------------------------------------------------------------------
+/// insertion and removal of points
+void Dnn4piCylinder::RemoveAndAddPoints(const vector<int> & indices_to_remove,
+				const vector<EtaPhi> & points_to_add,
+				vector<int> & indices_added,
+				vector<int> & indices_of_updated_neighbours) {
+  
+  vector<int> indices1, indices2;
+  
+  _DNN1->RemoveAndAddPoints(indices_to_remove,points_to_add,
+				      indices_added,indices1);
+
+  // create a vector with the remapped points (pi..3pi)
+  vector<EtaPhi> remapped_points(points_to_add.size());
+  for (size_t i = 0; i < points_to_add.size(); i++) {
+    remapped_points[i] = _remap_phi(points_to_add[i]);
+  }
+  _DNN2->RemoveAndAddPoints(indices_to_remove, remapped_points, 
+				      indices_added,indices2);
+  
+  // merge the two sequences of updated vertices, avoiding double entries
+  // of vertices with the same index
+  set<int> index_set;
+  unsigned int i;
+  for (i=0; i < indices1.size(); i++) {index_set.insert(indices1[i]);}
+  for (i=0; i < indices2.size(); i++) {index_set.insert(indices2[i]);}
+
+  indices_of_updated_neighbours.clear();
+  for (set<int>::iterator iter = index_set.begin(); 
+       iter != index_set.end(); iter++) {
+    indices_of_updated_neighbours.push_back(*iter);
+  }
+}
+
+FASTJET_END_NAMESPACE
+
+#endif //  DROP_CGAL 
Index: /trunk/Utilities/Fastjet/src/DnnPlane.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/DnnPlane.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/DnnPlane.cc	(revision 11)
@@ -0,0 +1,357 @@
+//STARTHEADER
+// $Id: DnnPlane.cc,v 1.1 2008-11-06 14:32:14 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#ifndef DROP_CGAL // in case we do not have the code for CGAL
+
+#include<set>
+#include<list>
+#include "fastjet/internal/DnnPlane.hh"
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+
+/// Initialiser from a set of points on an Eta-Phi plane, where both
+/// eta and phi can have arbitrary ranges
+DnnPlane::DnnPlane(const vector<EtaPhi> & input_points, 
+		   const bool & verbose ) {
+
+  _verbose = verbose;
+  int n = input_points.size();
+  
+  // construct Voronoi diagram in such a way as to get the vertex handles
+  // and remember to set CGAL info with the index of the vertex
+  SuperVertex sv;
+  for (int i = 0; i < n; i++) {
+    sv.vertex = 
+       _TR.insert(Point(input_points[i].first, input_points[i].second));
+
+    // we are not up to dealing with coincident vertices, so make 
+    // sure the user knows!
+    _CrashIfVertexPresent(sv.vertex, i);
+    
+    // we need to assicate an index to each vertex -- thus when we get
+    // a vertex (e.g. as a nearest neighbour) from CGAL, we will be
+    // able to figure out which particle it corresponded to.
+    sv.vertex->info() = i;
+    _supervertex.push_back(sv);    
+  }
+
+  // label infinite vertex info with negative index 
+  _TR.infinite_vertex()->info() = INFINITE_VERTEX;
+
+  // set up the structure that holds nearest distances and neighbours
+  for (int j = 0; j < n; j++) {_SetNearest(j);}
+
+}
+
+
+//----------------------------------------------------------------------
+/// Crashes if the given vertex handle already exists. Otherwise
+/// it does the bookkeeping for future such tests
+void DnnPlane::_CrashIfVertexPresent(
+	const Vertex_handle & vertex, const int & its_index) {
+  if (!_crash_on_coincidence) return;
+
+  // vertices that do not have the same geometric position as any
+  // other vertex so far added have info().val() == NEW_VERTEX -- this
+  // is ensured by the InitialisedInt class, which forms the "info"
+  // part of our
+  // CGAL::Triangulation_vertex_base_with_info_2<InitialisedInt,K>
+  //
+  // If the vertex coincides with one that already exists, then
+  // info().val() it's info().val() will have been updated (in
+  // DNN:DNN) to be equal to a vertex "index".
+  if (vertex->info().val() != NEW_VERTEX) {
+    ostringstream err;
+    err << "ERROR in DnnPlane::_CrashIfVertexPresent"
+	 <<endl << "Point "<<its_index<<" coincides with point "
+	 <<vertex->info().val() << endl;
+    throw DnnError(err.str());
+  } 
+}
+
+
+//----------------------------------------------------------------------
+/// remove the points labelled by the vector indices_to_remove, and
+/// add the points specified by the vector points_to_add
+/// (corresponding indices will be calculated automatically); the
+/// idea behind this routine is that the points to be added will
+/// somehow be close to the one or other of the points being removed
+/// and this can be used by the implementation to provide hints for
+/// inserting the new points in whatever structure it is using.  In a
+/// kt-algorithm the points being added will be a result of a
+/// combination of the points to be removed -- hence the proximity
+/// is (more or less) guaranteed.
+void DnnPlane::RemoveAndAddPoints(
+			  const vector<int> & indices_to_remove,
+			  const vector<EtaPhi> & points_to_add,
+			  vector<int> & indices_added,
+			  vector<int> & indices_of_updated_neighbours) {
+
+
+  // build set of UNION of Voronoi neighbours of a pair of nearest
+  // neighbours
+  set<int> NeighbourUnion;
+  // later on it will be convenient to have access to a set (rather
+  // than vector) of indices being removed
+  set<int> indices_removed;
+
+  // for each of the indices to be removed add the voronoi neighbourhood to
+  // the NeighbourUnion set.
+  for (size_t ir = 0; ir < indices_to_remove.size(); ir++) {
+    int index = indices_to_remove[ir];
+    indices_removed.insert(index);
+    if (_verbose) cout << " Starting  RemoveAndAddPoints" << endl; 
+    if (_verbose) cout << " point " << index << endl;			 
+    // have a circulators that will go round the Voronoi neighbours of
+    // _supervertex[index1].vertex
+    Vertex_circulator vc = _TR.incident_vertices(_supervertex[index].vertex);
+    Vertex_circulator done = vc;
+    do  {
+      // if a neighbouring vertex not the infinite vertex, then add it
+      // to our union of neighbouring vertices.
+      if (_verbose) cout << "examining " << vc->info().val() << endl;
+      if (vc->info().val() != INFINITE_VERTEX) {
+	// NB: from it=1 onwards occasionally it might already have
+	// been inserted -- but double insertion still leaves only one
+	// copy in the set, so there's no problem
+	NeighbourUnion.insert(vc->info().val());
+	if (_verbose) cout << "inserted " << vc->info().val() << endl;
+      } 
+    } while (++vc != done);
+  }
+  
+  if (_verbose) {
+    set<int>::iterator it = NeighbourUnion.begin();
+    cout << "Union of neighbours of combined points" << endl;
+    for ( ; it != NeighbourUnion.end(); ++it ) {
+      cout << *it << endl;
+    }
+  }
+
+  // update set, triangulation and supervertex info
+  for (size_t ir = 0; ir < indices_to_remove.size(); ir++) {
+    int index = indices_to_remove[ir];
+
+    // NeighbourUnion should not contain the points to be removed
+    // (because later we will assume they still exist).
+    NeighbourUnion.erase(indices_to_remove[ir]);
+    
+    // points to be removed should also be eliminated from the
+    // triangulation and the supervertex structure should be updated
+    // to reflect the fact that the points are no longer valid.
+    _TR.remove(_supervertex[index].vertex);
+    _supervertex[index].vertex = NULL;
+  }
+
+  // add new point: give a "hint" to the inserter that
+  // the new point should be added close to old points -- the easiest way 
+  // of getting this is to take a point from the NeighbourUnion AFTER we have
+  // removed point1, point2, and to get one of its incident faces.
+  // 
+  // This hinting improves speed by c. 25% for 10^4 points because it
+  // avoids the need for a costly (sqrt{N}) location step (at least
+  // with a non-hierarchical triangulation -- with a hierarchical one,
+  // this step could be done away with, though there will still be a
+  // cost of O(ln N) to pay.
+  // 
+  // For some reason inserting the point before the two removals
+  // slows things down by c. 25%. This importance of the order
+  // is not understood.
+  //
+  // At some point it might be worth trying to select the "nearest"
+  // of the various points in the neighbour union to avoid large 
+  // steps in cases where we have 0..2pi periodicity and the first member
+  // of the neighbour union happens to be on the wrong side.
+  Face_handle face;
+  if (indices_to_remove.size() > 0) {
+    // face can only be found if there were points to remove in first place
+    face = _TR.incident_faces(
+   	                   _supervertex[*NeighbourUnion.begin()].vertex);}
+  // make sure the output arrays are empty
+  indices_added.clear();
+  indices_of_updated_neighbours.clear();
+  for (size_t ia = 0; ia < points_to_add.size(); ia++) {
+    SuperVertex sv;
+    _supervertex.push_back(sv);
+    int index = _supervertex.size()-1;
+    indices_added.push_back(index);
+
+    if (indices_to_remove.size() > 0) {
+      // be careful of using face (for location hinting) only when it exists
+      _supervertex[index].vertex = _TR.insert(Point(points_to_add[ia].first, 
+				  points_to_add[ia].second),face);}
+    else { 
+      _supervertex[index].vertex = _TR.insert(Point(points_to_add[ia].first, 
+						    points_to_add[ia].second));
+    }
+    // we are not up to dealing with coincident vertices, so make 
+    // sure the user knows!
+    _CrashIfVertexPresent(_supervertex[index].vertex, index);
+    _supervertex[index].vertex->info() = index;
+    
+    // first find nearest neighbour of "newpoint" (shorthand for
+    // _supervertex[index].vertex); while we're at it, for each of the
+    // voronoi neighbours, "D", of newpoint, examine whether newpoint is
+    // closer to "D" than D's current nearest neighbour -- when this
+    // occurs, put D into indices_of_updated_neighbours.
+    // 
+    // manually put newpoint on indices_of_updated_neighbours
+    indices_of_updated_neighbours.push_back(index);
+    _SetAndUpdateNearest(index, indices_of_updated_neighbours);
+  }
+
+  // for Voronoi neighbours j of any of the removed points for which
+  // one of those removed points was the nearest neighbour,
+  // redetermine the nearest neighbour of j and add j onto the vector
+  // of indices_of_updated_neighbours.
+  set<int>::iterator it2 = NeighbourUnion.begin();
+  for ( ; it2 != NeighbourUnion.end(); ++it2 ) {
+    int j = *it2;
+    // the if avoids the vertex at infinity, which gets a negative index
+    if( j != INFINITE_VERTEX ) {
+      // this is where we check if the nearest neighbour of j was one
+      // of the removed points
+      if (indices_removed.count(_supervertex[j].NNindex)) {
+	if (_verbose) cout << "j " << j << endl;
+	_SetNearest(j);
+	indices_of_updated_neighbours.push_back(j);
+	if (_verbose) cout << "NN of " << j << " : " 
+			  << _supervertex[j].NNindex
+	                  << ", dist = " << _supervertex[j].NNdistance <<endl;
+      }
+    }
+  }
+
+}
+
+
+//----------------------------------------------------------------------
+/// Determines the index and distance of the nearest neighbour to 
+/// point j and puts the information into the _supervertex entry for j.
+void DnnPlane::_SetNearest (const int & j) {
+  Vertex_handle current = _supervertex[j].vertex;
+  Vertex_circulator vc = _TR.incident_vertices(current);
+  Vertex_circulator done = vc;
+  double dist;
+  double mindist = HUGE_DOUBLE; // change this to "HUGE" or max_double?
+  Vertex_handle nearest = _TR.infinite_vertex();
+
+  // when there is only one finite point left in the triangulation, 
+  // there are no triangles. Presumably this is why voronoi returns
+  // NULL for the incident vertex circulator. Check if this is
+  // happening before circulating over it... (Otherwise it crashes
+  // when looking for neighbours of last point)
+  if (vc != NULL) do { 
+    if ( vc->info().val() != INFINITE_VERTEX) {
+      // find distance between j and its Voronoi neighbour (vc)
+      if (_verbose) cout << current->info().val() << " " << vc->info().val() << endl;
+      dist = _euclid_distance(current->point(), vc->point());
+      // check if j is closer to vc than vc's currently registered
+      // nearest neighbour (and update things if it is)
+      if (dist < mindist) {
+	mindist = dist; nearest = vc; 
+	if (_verbose) cout << "nearer ";
+      } 
+      if (_verbose) cout << vc->point() << "; "<< dist << endl;
+    }
+  } while (++vc != done); // move on to next Voronoi neighbour
+  // set j's supervertex info about nearest neighbour
+  _supervertex[j].NNindex = nearest->info().val();
+  _supervertex[j].NNdistance = mindist;
+}
+
+//----------------------------------------------------------------------
+/// Determines and stores the nearest neighbour of j, and where
+/// necessary update the nearest-neighbour info of Voronoi neighbours
+/// of j;
+///
+/// For each voronoi neighbour D of j if the distance between j and D
+/// is less than D's own nearest neighbour, then update the
+/// nearest-neighbour info in D; push D's index onto 
+/// indices_of_updated_neighbours
+///
+/// Note that j is NOT pushed onto indices_of_updated_neighbours --
+/// if you want it there, put it there yourself.
+///
+/// NB: note that we have _SetAndUpdateNearest as a completely
+///     separate routine from _SetNearest because we want to
+///     use one single ciruclation over voronoi neighbours to find the
+///     nearest neighbour and to update the voronoi neighbours if need
+///     be.
+void DnnPlane::_SetAndUpdateNearest(
+			  const int & j, 
+			  vector<int> & indices_of_updated_neighbours) {
+
+  Vertex_handle current = _supervertex[j].vertex;
+  Vertex_circulator vc = _TR.incident_vertices(current);
+  Vertex_circulator done = vc;
+  double dist;
+  double mindist = HUGE_DOUBLE; // change this to "HUGE" or max_double?
+  Vertex_handle nearest = _TR.infinite_vertex();
+
+  // when there is only one finite point left in the triangulation, 
+  // there are no triangles. Presumably this is why voronoi returns
+  // NULL for the incident vertex circulator. Check if this is
+  // happening before circulating over it... (Otherwise it crashes
+  // when looking for neighbours of last point)
+  if (vc != NULL) do { 
+    if (vc->info().val() != INFINITE_VERTEX) {
+      if (_verbose) cout << current->info().val() << " " << vc->info().val() << endl;
+      // find distance between j and its Voronoi neighbour (vc)
+      dist = _euclid_distance(current->point(), vc->point());
+      // update the mindist if we are closer than anything found so far
+      if (dist < mindist) {
+	mindist = dist; nearest = vc; 
+	if (_verbose) cout << "nearer ";
+      } 
+      // find index corresponding to vc for easy manipulation
+      int vcindx = vc->info().val();
+      if (_verbose) cout << vc->point() << "; "<< dist << endl;
+      // check if j is closer to vc than vc's currently registered
+      // nearest neighbour (and update things if it is)
+      if (dist < _supervertex[vcindx].NNdistance) {
+	if (_verbose) cout << vcindx << "'s NN becomes " << current->info().val() << endl;
+	_supervertex[vcindx].NNdistance = dist;
+	_supervertex[vcindx].NNindex = j;
+	indices_of_updated_neighbours.push_back(vcindx);
+      }
+    }
+  } while (++vc != done); // move on to next Voronoi neighbour
+  // set j's supervertex info about nearest neighbour
+  _supervertex[j].NNindex = nearest->info().val();
+  _supervertex[j].NNdistance = mindist;
+}
+
+FASTJET_END_NAMESPACE
+
+#endif //  DROP_CGAL
Index: /trunk/Utilities/Fastjet/src/Error.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/Error.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/Error.cc	(revision 11)
@@ -0,0 +1,38 @@
+//STARTHEADER
+// $Id: Error.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/Error.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+bool Error::_print_errors = true;
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/GhostedAreaSpec.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/GhostedAreaSpec.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/GhostedAreaSpec.cc	(revision 11)
@@ -0,0 +1,97 @@
+//STARTHEADER
+// $Id: GhostedAreaSpec.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/GhostedAreaSpec.hh"
+#include<iostream>
+#include<sstream>
+
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+BasicRandom<double> GhostedAreaSpec::_random_generator;
+
+//======================================================================
+/// sets the detailed parameters for the ghosts (which may not be quite
+/// the same as those requested -- this is in order for things to fit
+/// in nicely into 2pi etc...
+void GhostedAreaSpec::_initialize() {
+  // add on area-measuring dummy particles
+  _drap = sqrt(_ghost_area);
+  _dphi = _drap;
+  _nphi = int(ceil(twopi/_dphi)); _dphi = twopi/_nphi;
+  _nrap = int(ceil(_ghost_maxrap/_drap)); _drap = _ghost_maxrap / _nrap;
+  _actual_ghost_area = _dphi * _drap;
+  _n_ghosts   = (2*_nrap+1)*_nphi;
+
+  // checkpoint the status of the random number generator.
+  checkpoint_random();
+  //_random_generator.info(cerr);
+}
+
+//----------------------------------------------------------------------
+/// adds the ghost 4-momenta to the vector of PseudoJet's
+void GhostedAreaSpec::add_ghosts(vector<PseudoJet> & event) const {
+  // add momenta for ghosts
+  for (int irap = -_nrap; irap <= _nrap; irap++) {
+    for (int iphi = 0; iphi < _nphi; iphi++) {
+     
+      // include random offsets for all quantities
+      double phi = (iphi+0.5) * _dphi + _dphi*(_our_rand()-0.5)*_grid_scatter;
+      double rap = irap * _drap + _drap*(_our_rand()-0.5)*_grid_scatter;
+      double kt = _mean_ghost_kt*(1+(_our_rand()-0.5)*_kt_scatter);
+
+      double pminus = kt*exp(-rap);
+      double pplus  = kt*exp(+rap);
+      double px = kt*sin(phi);
+      double py = kt*cos(phi);
+      //cout << kt<<" "<<rap<<" "<<phi<<"\n";
+      //if (phi>=twopi || phi < 0.0) cout << "Hey: "<< phi-twopi<<"\n";
+      PseudoJet mom(px,py,0.5*(pplus-pminus),0.5*(pplus+pminus));
+      event.push_back(mom);
+    }
+  }
+}
+
+string GhostedAreaSpec::description() const {
+
+  ostringstream ostr;
+  ostr << "ghosts of area " << actual_ghost_area() 
+       << " (had requested " << ghost_area() << ")"
+       << ", placed up to y = " << ghost_maxrap() 
+       << ", scattered wrt to perfect grid by (rel) " << grid_scatter() 
+       << ", mean_ghost_kt = " << mean_ghost_kt()
+       << ", rel kt_scatter =  " << kt_scatter()
+       << ", n repetitions of ghost distributions =  " << repeat();
+  return ostr.str();
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/JetDefinition.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/JetDefinition.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/JetDefinition.cc	(revision 11)
@@ -0,0 +1,191 @@
+//STARTHEADER
+// $Id: JetDefinition.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/JetDefinition.hh"
+#include "../include/fastjet/Error.hh"
+#include<sstream>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+string JetDefinition::description() const {
+  ostringstream name;
+  if (jet_algorithm() == plugin_algorithm) {
+    return plugin()->description();
+  } else if (jet_algorithm() == kt_algorithm) {
+    name << "Longitudinally invariant kt algorithm with R = " << R();
+    name << " and " << recombiner()->description();
+  } else if (jet_algorithm() == cambridge_algorithm) {
+    name << "Longitudinally invariant Cambridge/Aachen algorithm with R = " 
+	 << R() ;
+    name << " and " << recombiner()->description();
+  } else if (jet_algorithm() == antikt_algorithm) {
+    name << "Longitudinally invariant anti-kt algorithm with R = " 
+	 << R() ;
+    name << " and " << recombiner()->description();
+  } else if (jet_algorithm() == cambridge_for_passive_algorithm) {
+    name << "Longitudinally invariant Cambridge/Aachen algorithm with R = " 
+	 << R() << "and a special hack whereby particles with kt < " 
+         << extra_param() << "are treated as passive ghosts";
+  } else {
+    throw Error("Unrecognized jet_finder");
+  }
+  return name.str();
+}
+
+
+void JetDefinition::set_recombination_scheme(
+                               RecombinationScheme recomb_scheme) {
+  _default_recombiner = JetDefinition::DefaultRecombiner(recomb_scheme);
+  _recombiner = 0;
+}
+
+
+string JetDefinition::DefaultRecombiner::description() const {
+  switch(_recomb_scheme) {
+  case E_scheme:
+    return "E scheme recombination";
+  case pt_scheme:
+    return "pt scheme recombination";
+  case pt2_scheme:
+    return "pt2 scheme recombination";
+  case Et_scheme:
+    return "Et scheme recombination";
+  case Et2_scheme:
+    return "Et2 scheme recombination";
+  case BIpt_scheme:
+    return "boost-invariant pt scheme recombination";
+  case BIpt2_scheme:
+    return "boost-invariant pt2 scheme recombination";
+  default:
+    ostringstream err;
+    err << "DefaultRecombiner: unrecognized recombination scheme " 
+        << _recomb_scheme;
+    throw Error(err.str());
+  }
+}
+
+
+void JetDefinition::DefaultRecombiner::recombine(
+           const PseudoJet & pa, const PseudoJet & pb,
+           PseudoJet & pab) const {
+  
+  double weighta, weightb;
+
+  switch(_recomb_scheme) {
+  case E_scheme:
+    pab = pa + pb; 
+    pab.set_user_index(0);
+    return;
+  // all remaining schemes are massless recombinations and locally
+  // we just set weights, while the hard work is done below...
+  case pt_scheme:
+  case Et_scheme:
+  case BIpt_scheme:
+    weighta = pa.perp(); 
+    weightb = pb.perp();
+    break;
+  case pt2_scheme:
+  case Et2_scheme:
+  case BIpt2_scheme:
+    weighta = pa.perp2(); 
+    weightb = pb.perp2();
+    break;
+  default:
+    ostringstream err;
+    err << "DefaultRecombiner: unrecognized recombination scheme " 
+        << _recomb_scheme;
+    throw Error(err.str());
+  }
+
+  double perp_ab = pa.perp() + pb.perp();
+  if (perp_ab != 0.0) { // weights also non-zero...
+    double y_ab    = (weighta * pa.rap() + weightb * pb.rap())/(weighta+weightb);
+    
+    // take care with periodicity in phi...
+    double phi_a = pa.phi(), phi_b = pb.phi();
+    if (phi_a - phi_b > pi)  phi_b += twopi;
+    if (phi_a - phi_b < -pi) phi_b -= twopi;
+    double phi_ab = (weighta * phi_a + weightb * phi_b)/(weighta+weightb);
+    
+    pab = PseudoJet(perp_ab*cos(phi_ab),
+		    perp_ab*sin(phi_ab),
+		    perp_ab*sinh(y_ab),
+		    perp_ab*cosh(y_ab));
+  } else { // weights are zero
+    pab = PseudoJet(0.0,0.0,0.0,0.0);
+  }
+  pab.set_user_index(0);
+}
+
+
+void JetDefinition::DefaultRecombiner::preprocess(PseudoJet & p) const {
+  switch(_recomb_scheme) {
+  case E_scheme:
+  case BIpt_scheme:
+  case BIpt2_scheme:
+    break;
+  case pt_scheme:
+  case pt2_scheme:
+    {
+      // these schemes (as in the ktjet implementation) need massless
+      // initial 4-vectors with essentially E=|p|.
+      double newE = sqrt(p.perp2()+p.pz()*p.pz());
+      int    user_index = p.user_index();
+      p = PseudoJet(p.px(), p.py(), p.pz(), newE);
+      p.set_user_index(user_index);
+    }
+    break;
+  case Et_scheme:
+  case Et2_scheme:
+    {
+      // these schemes (as in the ktjet implementation) need massless
+      // initial 4-vectors with essentially E=|p|.
+      double rescale = p.E()/sqrt(p.perp2()+p.pz()*p.pz());
+      int    user_index = p.user_index();
+      p = PseudoJet(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
+      p.set_user_index(user_index);
+    }
+    break;
+  default:
+    ostringstream err;
+    err << "DefaultRecombiner: unrecognized recombination scheme " 
+        << _recomb_scheme;
+    throw Error(err.str());
+  }
+}
+
+void JetDefinition::Plugin::set_ghost_separation_scale(double scale) const {
+      throw Error("set_ghost_separation_scale not supported");
+}
+ 
+
+FASTJET_END_NAMESPACE
Index: /trunk/Utilities/Fastjet/src/MinHeap.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/MinHeap.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/MinHeap.cc	(revision 11)
@@ -0,0 +1,129 @@
+//STARTHEADER
+// $Id: MinHeap.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/internal/MinHeap.hh"
+#include<iostream>
+#include<cmath>
+#include<limits>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+//----------------------------------------------------------------------
+/// construct the MinHeap; structure will be as follows:
+///   . _heap[0].minloc points to globally smallest entry
+///     _heap[1].minloc points to smallest entry in one half of heap
+///     _heap[2].minloc points to smallest entry in other half of heap
+///
+///   . for _heap[i], the "parent" is to be found at (i-1)/2
+void MinHeap::_initialise(const std::vector<double> & values){
+  
+  // fill the high-range of the heap with the largest possible value
+  // (minloc of each entry is itself)
+  for (unsigned i = values.size(); i < _heap.size(); i++) {
+    _heap[i].value = std::numeric_limits<double>::max();
+    _heap[i].minloc = &(_heap[i]);
+  }
+
+  // fill the rest of the heap with the actual values
+  // (minloc of each entry is itself)
+  for (unsigned i = 0; i < values.size(); i++) {
+    _heap[i].value = values[i];
+    _heap[i].minloc = &(_heap[i]);
+  }
+  
+  // now adjust the minlocs so that everything is OK...
+  for (unsigned i = _heap.size()-1; i > 0; i--) {
+    ValueLoc * parent = &(_heap[(i-1)/2]);
+    ValueLoc * here   = &(_heap[i]);
+    if (here->minloc->value < parent->minloc->value) {
+      parent->minloc = here->minloc;
+    }
+  }
+  //cout << minloc() << " "<<sqrt(minval())<<endl;
+  //cout << sqrt(_heap[47].value)<<endl;
+  //cout << sqrt(_heap[48].value)<<endl;
+  //cout << sqrt(_heap[25].value)<<endl;
+}
+
+
+//----------------------------------------------------------------------
+void MinHeap::update(unsigned int loc, double new_value) {
+  
+
+  assert(loc < _heap.size());
+  ValueLoc * start = &(_heap[loc]);
+
+  // if the minloc is somewhere below us and our value is no smaller
+  // than the previous value, we can't possibly change the minloc
+  if (start->minloc != start && !(new_value < start->minloc->value)) {
+    start->value = new_value;
+    //std::cout << "                     had easy exit\n";
+    return;
+  }
+
+  // update the value and put a temporary location
+  start->value = new_value;
+  start->minloc = start;
+  // warn that a change has been made at this place
+  bool change_made = true;
+  // to make sure we don't go off edge...
+  ValueLoc * heap_end = (&(_heap[0])) + _heap.size();
+
+  // now work our way up the heap
+  while(change_made) {
+    ValueLoc * here = &(_heap[loc]);
+    change_made     = false;
+
+    // if we were pointing to start, then we must re-initialise things
+    if (here->minloc == start) {
+      here->minloc = here; change_made = true;
+    }
+
+    // now compare current location to children (at 2*loc+1, 2*loc+2)
+    ValueLoc * child = &(_heap[2*loc+1]);
+    if (child < heap_end && child->minloc->value < here->minloc->value ) {
+      here->minloc = child->minloc;
+      change_made = true;}
+    child++;
+    if (child < heap_end && child->minloc->value < here->minloc->value ) {
+      here->minloc = child->minloc;
+      change_made = true;}
+    
+    // then we move up (loc ->(loc-1)/2) if there's anywhere to go 
+    if (loc == 0) {break;}
+    loc = (loc-1)/2;
+  }
+
+}
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/PseudoJet.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/PseudoJet.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/PseudoJet.cc	(revision 11)
@@ -0,0 +1,385 @@
+//STARTHEADER
+// $Id: PseudoJet.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 2005-2006, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+#include "../include/fastjet/Error.hh"
+#include "../include/fastjet/PseudoJet.hh"
+#include<valarray>
+#include<iostream>
+#include<sstream>
+#include<cmath>
+#include<algorithm>
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+
+
+//----------------------------------------------------------------------
+// another constructor...
+PseudoJet::PseudoJet(const double px, const double py, const double pz, const double E) {
+  
+  _E  = E ;
+  _px = px;
+  _py = py;
+  _pz = pz;
+
+  this->_finish_init();
+
+  // some default values for the history and user indices
+  _reset_indices();
+
+}
+
+
+//----------------------------------------------------------------------
+/// do standard end of initialisation
+void PseudoJet::_finish_init () {
+  _kt2 = this->px()*this->px() + this->py()*this->py();
+  if (_kt2 == 0.0) {
+    _phi = 0.0; } 
+  else {
+    _phi = atan2(this->py(),this->px());
+  }
+  if (_phi < 0.0) {_phi += twopi;}
+  if (_phi >= twopi) {_phi -= twopi;} // can happen if phi=-|eps<1e-15|?
+  if (this->E() == abs(this->pz()) && _kt2 == 0) {
+    // Point has infinite rapidity -- convert that into a very large
+    // number, but in such a way that different 0-pt momenta will have
+    // different rapidities (so as to lift the degeneracy between
+    // them) [this can be relevant at parton-level]
+    double MaxRapHere = MaxRap + abs(this->pz());
+    if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
+  } else {
+    // get the rapidity in a way that's modestly insensitive to roundoff
+    // error when things pz,E are large (actually the best we can do without
+    // explicit knowledge of mass)
+    double effective_m2 = max(0.0,m2()); // force non tachyonic mass
+    double E_plus_pz    = _E + abs(_pz); // the safer of p+, p-
+    // p+/p- = (p+ p-) / (p-)^2 = (kt^2+m^2)/(p-)^2
+    _rap = 0.5*log((_kt2 + effective_m2)/(E_plus_pz*E_plus_pz));
+    if (_pz > 0) {_rap = - _rap;}
+  }
+
+  //// original determination 
+  //if (this->E() != abs(this->pz())) {
+  //  _rap = 0.5*log((this->E() + this->pz())/(this->E() - this->pz()));
+  //    } else {
+  //  // Overlapping points can give problems. Let's lift the degeneracy
+  //  // in case of multiple 0-pT points (can be found at parton-level)
+  //  double MaxRapHere = MaxRap + abs(this->pz());
+  //  if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
+  //}
+}
+
+
+//----------------------------------------------------------------------
+// return a valarray four-momentum
+valarray<double> PseudoJet::four_mom() const {
+  valarray<double> mom(4);
+  mom[0] = _px;
+  mom[1] = _py;
+  mom[2] = _pz;
+  mom[3] = _E ;
+  return mom;
+}
+
+//----------------------------------------------------------------------
+// Return the component corresponding to the specified index.
+// taken from CLHEP
+double PseudoJet::operator () (int i) const {
+  switch(i) {
+  case X:
+    return px();
+  case Y:
+    return py();
+  case Z:
+    return pz();
+  case T:
+    return e();
+  default:
+    ostringstream err;
+    err << "PseudoJet subscripting: bad index (" << i << ")";
+    throw Error(err.str());
+  }
+  return 0.;
+}  
+
+//----------------------------------------------------------------------
+// return the pseudorapidity
+double PseudoJet::pseudorapidity() const {
+  if (px() == 0.0 && py() ==0.0) return MaxRap;
+  if (pz() == 0.0) return 0.0;
+
+  double theta = atan(perp()/pz());
+  if (theta < 0) theta += pi;
+  return -log(tan(theta/2));
+}
+
+//----------------------------------------------------------------------
+// return "sum" of two pseudojets
+PseudoJet operator+ (const PseudoJet & jet1, const PseudoJet & jet2) {
+  //return PseudoJet(jet1.four_mom()+jet2.four_mom());
+  return PseudoJet(jet1.px()+jet2.px(),
+		   jet1.py()+jet2.py(),
+		   jet1.pz()+jet2.pz(),
+		   jet1.E() +jet2.E()  );
+} 
+
+//----------------------------------------------------------------------
+// return difference of two pseudojets
+PseudoJet operator- (const PseudoJet & jet1, const PseudoJet & jet2) {
+  //return PseudoJet(jet1.four_mom()-jet2.four_mom());
+  return PseudoJet(jet1.px()-jet2.px(),
+		   jet1.py()-jet2.py(),
+		   jet1.pz()-jet2.pz(),
+		   jet1.E() -jet2.E()  );
+} 
+
+//----------------------------------------------------------------------
+// return the product, coeff * jet
+PseudoJet operator* (double coeff, const PseudoJet & jet) {
+  //return PseudoJet(coeff*jet.four_mom());
+  // the following code is hopefully more efficient
+  PseudoJet coeff_times_jet(jet);
+  coeff_times_jet *= coeff;
+  return coeff_times_jet;
+} 
+
+//----------------------------------------------------------------------
+// return the product, coeff * jet
+PseudoJet operator* (const PseudoJet & jet, double coeff) {
+  return coeff*jet;
+} 
+
+//----------------------------------------------------------------------
+// return the ratio, jet / coeff
+PseudoJet operator/ (const PseudoJet & jet, double coeff) {
+  return (1.0/coeff)*jet;
+} 
+
+//----------------------------------------------------------------------
+/// multiply the jet's momentum by the coefficient
+void PseudoJet::operator*=(double coeff) {
+  _px *= coeff;
+  _py *= coeff;
+  _pz *= coeff;
+  _E  *= coeff;
+  _kt2*= coeff*coeff;
+  // phi and rap are unchanged
+}
+
+//----------------------------------------------------------------------
+/// divide the jet's momentum by the coefficient
+void PseudoJet::operator/=(double coeff) {
+  (*this) *= 1.0/coeff;
+}
+
+
+//----------------------------------------------------------------------
+/// add the other jet's momentum to this jet
+void PseudoJet::operator+=(const PseudoJet & other_jet) {
+  _px += other_jet._px;
+  _py += other_jet._py;
+  _pz += other_jet._pz;
+  _E  += other_jet._E ;
+  _finish_init(); // we need to recalculate phi,rap,kt2
+}
+
+
+//----------------------------------------------------------------------
+/// subtract the other jet's momentum from this jet
+void PseudoJet::operator-=(const PseudoJet & other_jet) {
+  _px -= other_jet._px;
+  _py -= other_jet._py;
+  _pz -= other_jet._pz;
+  _E  -= other_jet._E ;
+  _finish_init(); // we need to recalculate phi,rap,kt2
+}
+
+
+//----------------------------------------------------------------------
+/// transform this jet (given in the rest frame of prest) into a jet
+/// in the lab frame;
+//
+// NB: code adapted from that in herwig f77 (checked how it worked
+// long ago)
+PseudoJet & PseudoJet::boost(const PseudoJet & prest) {
+  
+  if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0) 
+    return *this;
+
+  double m = prest.m();
+  assert(m != 0);
+
+  double pf4  = (  px()*prest.px() + py()*prest.py()
+                 + pz()*prest.pz() + E()*prest.E() )/m;
+  double fn   = (pf4 + E()) / (prest.E() + m);
+  _px +=  fn*prest.px();
+  _py +=  fn*prest.py();
+  _pz +=  fn*prest.pz();
+  _E = pf4;
+
+  _finish_init(); // we need to recalculate phi,rap,kt2
+  return *this;
+}
+
+
+//----------------------------------------------------------------------
+/// transform this jet (given in the rest frame of prest) into a jet
+/// in the lab frame;
+//
+// NB: code adapted from that in herwig f77 (checked how it worked
+// long ago)
+PseudoJet & PseudoJet::unboost(const PseudoJet & prest) {
+  
+  if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0) 
+    return *this;
+
+  double m = prest.m();
+  assert(m != 0);
+
+  double pf4  = ( -px()*prest.px() - py()*prest.py()
+                 - pz()*prest.pz() + E()*prest.E() )/m;
+  double fn   = (pf4 + E()) / (prest.E() + m);
+  _px -=  fn*prest.px();
+  _py -=  fn*prest.py();
+  _pz -=  fn*prest.pz();
+  _E = pf4;
+
+  _finish_init(); // we need to recalculate phi,rap,kt2
+  return *this;
+}
+
+
+//----------------------------------------------------------------------
+/// returns true if the momenta of the two input jets are identical
+bool have_same_momentum(const PseudoJet & jeta, const PseudoJet & jetb) {
+  return jeta.px() == jetb.px()
+    &&   jeta.py() == jetb.py()
+    &&   jeta.pz() == jetb.pz()
+    &&   jeta.E()  == jetb.E();
+}
+
+
+//----------------------------------------------------------------------
+/// return a pseudojet with the given pt, y, phi and mass
+PseudoJet PtYPhiM(double pt, double y, double phi, double m) {
+  double ptm = sqrt(pt*pt+m*m);
+  return PseudoJet(pt*cos(phi), pt*sin(phi), ptm*sinh(y), ptm*cosh(y));
+}
+
+
+//----------------------------------------------------------------------
+// return kt-distance between this jet and another one
+double PseudoJet::kt_distance(const PseudoJet & other) const {
+  //double distance = min(this->kt2(), other.kt2());
+  double distance = min(_kt2, other._kt2);
+  double dphi = abs(_phi - other._phi);
+  if (dphi > pi) {dphi = twopi - dphi;}
+  double drap = _rap - other._rap;
+  distance = distance * (dphi*dphi + drap*drap);
+  return distance;
+}
+
+
+//----------------------------------------------------------------------
+// return squared cylinder (eta-phi) distance between this jet and another one
+double PseudoJet::plain_distance(const PseudoJet & other) const {
+  double dphi = abs(_phi - other._phi);
+  if (dphi > pi) {dphi = twopi - dphi;}
+  double drap = _rap - other._rap;
+  return (dphi*dphi + drap*drap);
+}
+
+//----------------------------------------------------------------------
+// sort the indices so that values[indices[0..n-1]] is sorted
+// into increasing order 
+void sort_indices(vector<int> & indices, 
+			 const vector<double> & values) {
+  IndexedSortHelper index_sort_helper(&values);
+  sort(indices.begin(), indices.end(), index_sort_helper);
+}
+
+//----------------------------------------------------------------------
+/// given a vector of values with a one-to-one correspondence with the
+/// vector of objects, sort objects into an order such that the
+/// associated values would be in increasing order
+template<class T> vector<T>  objects_sorted_by_values(
+                       const vector<T> & objects, 
+		       const vector<double> & values) {
+
+  assert(objects.size() == values.size());
+
+  // get a vector of indices
+  vector<int> indices(values.size());
+  for (size_t i = 0; i < indices.size(); i++) {indices[i] = i;}
+  
+  // sort the indices
+  sort_indices(indices, values);
+  
+  // copy the objects 
+  vector<T> objects_sorted(objects.size());
+  
+  // place the objects in the correct order
+  for (size_t i = 0; i < indices.size(); i++) {
+    objects_sorted[i] = objects[indices[i]];
+  }
+
+  return objects_sorted;
+}
+
+//----------------------------------------------------------------------
+/// return a vector of jets sorted into decreasing kt2
+vector<PseudoJet> sorted_by_pt(const vector<PseudoJet> & jets) {
+  vector<double> minus_kt2(jets.size());
+  for (size_t i = 0; i < jets.size(); i++) {minus_kt2[i] = -jets[i].kt2();}
+  return objects_sorted_by_values(jets, minus_kt2);
+}
+
+//----------------------------------------------------------------------
+/// return a vector of jets sorted into increasing rapidity
+vector<PseudoJet> sorted_by_rapidity(const vector<PseudoJet> & jets) {
+  vector<double> rapidities(jets.size());
+  for (size_t i = 0; i < jets.size(); i++) {rapidities[i] = jets[i].rap();}
+  return objects_sorted_by_values(jets, rapidities);
+}
+
+//----------------------------------------------------------------------
+/// return a vector of jets sorted into decreasing energy
+vector<PseudoJet> sorted_by_E(const vector<PseudoJet> & jets) {
+  vector<double> energies(jets.size());
+  for (size_t i = 0; i < jets.size(); i++) {energies[i] = -jets[i].E();}
+  return objects_sorted_by_values(jets, energies);
+}
+
+
+FASTJET_END_NAMESPACE
+
Index: /trunk/Utilities/Fastjet/src/RangeDefinition.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/RangeDefinition.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/RangeDefinition.cc	(revision 11)
@@ -0,0 +1,57 @@
+//STARTHEADER
+// $Id: RangeDefinition.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 2005-2007, Matteo Cacciari and Gavin Salam
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet.
+//
+//  FastJet is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  The algorithms that underlie FastJet have required considerable
+//  development and are described in hep-ph/0512210. If you use
+//  FastJet as part of work towards a scientific publication, please
+//  include a citation to the FastJet paper.
+//
+//  FastJet is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with FastJet; if not, write to the Free Software
+//  Foundation, Inc.:
+//      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------
+//ENDHEADER
+
+#include "../include/fastjet/RangeDefinition.hh"
+
+FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
+
+using namespace std;
+ 
+/// calculate, and set in _total_area, the area with a numerical test
+/// takes a reasonable time with rapmax = 10, npoints = 100
+void RangeDefinition::_numerical_total_area(double rapmax, int npoints) {
+
+      int count = 0;
+      double deltaphi = twopi/double(npoints);
+      double deltarap = 2.0*rapmax/double(npoints);
+      double phi = 0.0;
+      for(int i = 0; i < npoints; i++) {
+        double rap = -rapmax;
+        for (int j = 0; j < npoints; j++) {
+	  if ( is_in_range(rap,phi) ) { count++; }
+          rap += deltarap;
+        }
+        phi += deltaphi;
+      }
+
+      _total_area = double(count)/double(npoints*npoints)*2.0*twopi*rapmax;
+}
+
+FASTJET_END_NAMESPACE
Index: /trunk/Utilities/Fastjet/src/Voronoi.cc
===================================================================
--- /trunk/Utilities/Fastjet/src/Voronoi.cc	(revision 11)
+++ /trunk/Utilities/Fastjet/src/Voronoi.cc	(revision 11)
@@ -0,0 +1,1066 @@
+//STARTHEADER
+// $Id: Voronoi.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
+//
+// Copyright (c) 1994 by AT&T Bell Laboratories (see below)
+//
+//
+//----------------------------------------------------------------------
+// This file is included as part of FastJet but was mostly written by
+// S. Fortune in C, put into C++ with memory management by S
+// O'Sullivan, and with further interface and memory management
+// modifications by Gregory Soyez.
+//
+// Permission to use, copy, modify, and distribute this software for
+// any purpose without fee is hereby granted, provided that this
+// entire notice is included in all copies of any software which is or
+// includes a copy or modification of this software and in all copies
+// of the supporting documentation for such software. THIS SOFTWARE IS
+// BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY.
+// IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY REPRESENTATION
+// OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
+// SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+//
+//----------------------------------------------------------------------
+//ENDHEADER
+
+
+/*
+ * The author of this software is Steven Fortune.  
+ * Copyright (c) 1994 by AT&T Bell Laboratories.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/* 
+ * This code was originally written by Stephan Fortune in C code.  I,
+ * Shane O'Sullivan, have since modified it, encapsulating it in a C++
+ * class and, fixing memory leaks and adding accessors to the Voronoi
+ * Edges.  Permission to use, copy, modify, and distribute this
+ * software for any purpose without fee is hereby granted, provided
+ * that this entire notice is included in all copies of any software
+ * which is or includes a copy or modification of this software and in
+ * all copies of the supporting documentation for such software.  THIS
+ * SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <stdio.h>
+#include "../include/fastjet/internal/Voronoi.hh"
+
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE
+
+VoronoiDiagramGenerator::VoronoiDiagramGenerator(){
+  siteidx = 0;
+  sites = NULL;
+  parent_sites = NULL;
+
+  allMemoryList = new FreeNodeArrayList;
+  allMemoryList->memory = NULL;
+  allMemoryList->next = NULL;
+  currentMemoryBlock = allMemoryList;
+  allEdges = NULL;
+  iteratorEdges = 0;
+  minDistanceBetweenSites = 0;
+
+  ELhash = NULL;
+  PQhash = NULL;
+}
+
+VoronoiDiagramGenerator::~VoronoiDiagramGenerator(){
+  cleanup();
+  cleanupEdges();
+
+  if (allMemoryList != NULL)
+    delete allMemoryList;
+}
+
+
+
+bool VoronoiDiagramGenerator::generateVoronoi(vector<Point> *_parent_sites,
+					      double minX, double maxX, 
+					      double minY, double maxY, 
+					      double minDist){
+  cleanup();
+  cleanupEdges();
+  int i;
+  double x, y;
+
+  minDistanceBetweenSites = minDist;
+
+  parent_sites = _parent_sites;
+
+  nsites = n_parent_sites = parent_sites->size();
+  plot = 0;
+  triangulate = 0;	
+  debug = 1;
+  sorted = 0; 
+  freeinit(&sfl, sizeof (Site));
+		
+  //sites = (Site *) myalloc(nsites*sizeof( *sites));
+  sites = (Site *) myalloc(nsites*sizeof( Site));
+  //parent_sites = (Site *) myalloc(nsites*sizeof( Site));
+ 
+  if (sites == 0)
+    return false;
+
+  xmax = xmin = (*parent_sites)[0].x;
+  ymax = ymin = (*parent_sites)[0].y;
+  
+  for(i=0;i<nsites;i++){
+    x = (*parent_sites)[i].x;
+    y = (*parent_sites)[i].y;
+    sites[i].coord.x = x;
+    sites[i].coord.y = y;
+    sites[i].sitenbr = i;
+    sites[i].refcnt  = 0;
+    
+    if (x<xmin)
+      xmin=x;
+    else if (x>xmax)
+      xmax=x;
+    
+    if (y<ymin)
+      ymin=y;
+    else if (y>ymax)
+      ymax=y;
+  }
+	
+  qsort(sites, nsites, sizeof (*sites), scomp);
+	
+  siteidx = 0;
+  geominit();
+  double temp = 0;
+  if(minX > maxX){
+    temp = minX;
+    minX = maxX;
+    maxX = temp;
+  }
+  if(minY > maxY){
+    temp = minY;
+    minY = maxY;
+    maxY = temp;
+  }
+  borderMinX = minX;
+  borderMinY = minY;
+  borderMaxX = maxX;
+  borderMaxY = maxY;
+	
+  siteidx = 0;
+  voronoi(triangulate);
+
+  return true;
+}
+
+bool VoronoiDiagramGenerator::ELinitialize(){
+  int i;
+  freeinit(&hfl, sizeof(Halfedge));
+  ELhashsize = 2 * sqrt_nsites;
+  //ELhash = (Halfedge **) myalloc ( sizeof *ELhash * ELhashsize);
+  ELhash = (Halfedge **) myalloc ( sizeof(Halfedge*)*ELhashsize);
+  
+  if(ELhash == 0)
+    return false;
+  
+  for(i=0; i<ELhashsize; i +=1) ELhash[i] = (Halfedge *)NULL;
+  ELleftend = HEcreate((Edge*) NULL, 0);
+  ELrightend = HEcreate((Edge*) NULL, 0);
+  ELleftend->ELleft = (Halfedge*) NULL;
+  ELleftend->ELright = ELrightend;
+  ELrightend->ELleft = ELleftend;
+  ELrightend->ELright = (Halfedge*) NULL;
+  ELhash[0] = ELleftend;
+  ELhash[ELhashsize-1] = ELrightend;
+
+  return true;
+}
+
+
+Halfedge* VoronoiDiagramGenerator::HEcreate(Edge *e,int pm){
+  Halfedge *answer;
+  answer = (Halfedge*) getfree(&hfl);
+  answer->ELedge = e;
+  answer->ELpm = pm;
+  answer->PQnext = (Halfedge*) NULL;
+  answer->vertex = (Site*) NULL;
+  answer->ELrefcnt = 0;
+  return answer;
+}
+
+
+void VoronoiDiagramGenerator::ELinsert(Halfedge *lb, Halfedge *newHe)
+{
+  newHe->ELleft = lb;
+  newHe->ELright = lb->ELright;
+  (lb->ELright)->ELleft = newHe;
+  lb->ELright = newHe;
+}
+
+
+/* Get entry from hash table, pruning any deleted nodes */
+Halfedge* VoronoiDiagramGenerator::ELgethash(int b){
+  Halfedge *he;
+	
+  if ((b<0) || (b>=ELhashsize)) 
+    return (Halfedge *) NULL;
+
+  he = ELhash[b]; 
+  if ((he==(Halfedge*) NULL) || (he->ELedge!=(Edge*) DELETED)) 
+    return he;
+	
+  /* Hash table points to deleted half edge.  Patch as necessary. */
+  ELhash[b] = (Halfedge*) NULL;
+  if ((he->ELrefcnt -= 1) == 0) 
+    makefree((Freenode*)he, &hfl);
+  return (Halfedge*) NULL;
+}	
+
+Halfedge * VoronoiDiagramGenerator::ELleftbnd(Point *p){
+  int i, bucket;
+  Halfedge *he;
+	
+  /* Use hash table to get close to desired halfedge */
+  // use the hash function to find the place in the hash map that this
+  // HalfEdge should be
+  bucket = (int)((p->x - xmin)/deltax * ELhashsize);	
+
+  // make sure that the bucket position in within the range of the
+  //hash array
+  if (bucket<0) bucket =0;
+  if (bucket>=ELhashsize) bucket = ELhashsize - 1;
+
+  he = ELgethash(bucket);
+
+  // if the HE isn't found, search backwards and forwards in the hash
+  // map for the first non-null entry
+  if (he == (Halfedge*) NULL){   
+    for(i=1;1;i++){	
+      if ((he=ELgethash(bucket-i)) != (Halfedge*) NULL) 
+	break;
+      if ((he=ELgethash(bucket+i)) != (Halfedge*) NULL) 
+	break;
+    };
+    totalsearch += i;
+  };
+  ntry += 1;
+  /* Now search linear list of halfedges for the correct one */
+  if ((he==ELleftend)  || (he != ELrightend && right_of(he,p))){
+    do{
+      he = he->ELright;
+    } while (he!=ELrightend && right_of(he,p));
+      // keep going right on the list until either the end is reached,
+      // or you find the 1st edge which the point
+      he = he->ELleft;	//isn't to the right of
+  } else 
+    // if the point is to the left of the HalfEdge, then search left
+    // for the HE just to the left of the point
+    do{
+      he = he->ELleft;
+    } while ((he!=ELleftend )&& (!right_of(he,p)));
+		
+  /* Update hash table and reference counts */
+  if ((bucket > 0) && (bucket <ELhashsize-1)){	
+    if(ELhash[bucket] != (Halfedge *) NULL){
+      ELhash[bucket]->ELrefcnt -= 1;
+    }
+    ELhash[bucket] = he;
+    ELhash[bucket]->ELrefcnt += 1;
+  };
+
+  return he;
+}
+
+
+/* This delete routine can't reclaim node, since pointers from hash
+   table may be present.   */
+void VoronoiDiagramGenerator::ELdelete(Halfedge *he){
+  (he->ELleft)->ELright = he->ELright;
+  (he->ELright)->ELleft = he->ELleft;
+  he->ELedge = (Edge*) DELETED;
+}
+
+
+Halfedge* VoronoiDiagramGenerator::ELright(Halfedge *he){
+  return he->ELright;
+}
+
+
+Halfedge* VoronoiDiagramGenerator::ELleft(Halfedge *he){
+  return he->ELleft;
+}
+
+
+Site * VoronoiDiagramGenerator::leftreg(Halfedge *he){
+  if (he->ELedge == (Edge*) NULL) 
+    return(bottomsite);
+  return (he->ELpm == le) 
+    ? he->ELedge->reg[le] 
+    : he->ELedge->reg[re];
+}
+
+Site * VoronoiDiagramGenerator::rightreg(Halfedge *he){
+  if (he->ELedge == (Edge*) NULL)
+    // if this halfedge has no edge, return the bottom site (whatever
+    // that is)
+    return bottomsite;
+  
+  // if the ELpm field is zero, return the site 0 that this edge
+  // bisects, otherwise return site number 1
+  return (he->ELpm == le)
+    ? he->ELedge->reg[re] 
+    : he->ELedge->reg[le];
+}
+
+void VoronoiDiagramGenerator::geominit(){
+  double sn;
+  
+  freeinit(&efl, sizeof(Edge));
+  nvertices = 0;
+  nedges = 0;
+  sn = (double)nsites+4;
+  sqrt_nsites = (int)sqrt(sn);
+  deltay = ymax - ymin;
+  deltax = xmax - xmin;
+}
+
+
+Edge * VoronoiDiagramGenerator::bisect(Site *s1, Site *s2){
+  double dx,dy,adx,ady;
+  Edge *newedge;	
+
+  newedge = (Edge*) getfree(&efl);
+	
+  newedge->reg[0] = s1; //store the sites that this edge is bisecting
+  newedge->reg[1] = s2;
+  ref(s1); 
+  ref(s2);
+
+  // to begin with, there are no endpoints on the bisector - it goes
+  // to infinity
+  newedge->ep[0] = (Site*) NULL;
+  newedge->ep[1] = (Site*) NULL;
+  
+  // get the difference in x dist between the sites
+  dx = s2->coord.x - s1->coord.x;
+  dy = s2->coord.y - s1->coord.y;
+
+  // make sure that the difference is positive
+  adx = dx>0 ? dx : -dx;
+  ady = dy>0 ? dy : -dy;
+
+  // get the slope of the line
+  newedge->c = (double)(s1->coord.x * dx + s1->coord.y * dy
+			+ (dx*dx + dy*dy)*0.5);
+
+  if (adx>ady){	
+    //set formula of line, with x fixed to 1
+    newedge->a = 1.0; newedge->b = dy/dx; newedge->c /= dx;
+  } else {	
+    //set formula of line, with y fixed to 1
+    newedge->b = 1.0; newedge->a = dx/dy; newedge->c /= dy;
+  }
+	
+  newedge->edgenbr = nedges;
+  nedges++;
+
+  return newedge;
+}
+
+
+// create a new site where the HalfEdges el1 and el2 intersect - note
+// that the Point in the argument list is not used, don't know why
+// it's there
+Site* VoronoiDiagramGenerator::intersect(Halfedge *el1, Halfedge *el2, Point *p){
+  Edge *e1,*e2, *e;
+  Halfedge *el;
+  double d, xint, yint;
+  int right_of_site;
+  Site *v;
+	
+  e1 = el1->ELedge;
+  e2 = el2->ELedge;
+  if ((e1==(Edge*)NULL) || (e2==(Edge*)NULL)) 
+    return ((Site*) NULL);
+
+  // if the two edges bisect the same parent, return null
+  if (e1->reg[1] == e2->reg[1]) 
+    return (Site*) NULL;
+	
+  d = e1->a * e2->b - e1->b * e2->a;
+  if (-1.0e-10<d && d<1.0e-10) 
+    return (Site*) NULL;
+	
+  xint = (e1->c*e2->b - e2->c*e1->b)/d;
+  yint = (e2->c*e1->a - e1->c*e2->a)/d;
+
+  volatile double local_y1 = e1->reg[1]->coord.y;
+  volatile double local_y2 = e2->reg[1]->coord.y;
+	
+  if( (local_y1 < local_y2) ||
+      ((local_y1 == local_y2) &&
+       (e1->reg[1]->coord.x <  e2->reg[1]->coord.x)) ){	
+    el = el1; 
+    e = e1;
+  } else {	
+    el = el2; 
+    e = e2;
+  }
+	
+  right_of_site = xint >= e->reg[1]->coord.x;
+  if ((right_of_site && el->ELpm == le) || (!right_of_site && el->ELpm == re)) 
+    return (Site*) NULL;
+	
+  // create a new site at the point of intersection - this is a new
+  // vector event waiting to happen
+  v = (Site*) getfree(&sfl);
+  v->refcnt = 0;
+  v->coord.x = xint;
+  v->coord.y = yint;
+  return v;
+}
+
+//HERE
+
+/* returns 1 if p is to right of halfedge e */
+int VoronoiDiagramGenerator::right_of(Halfedge *el,Point *p)
+{
+  Edge *e;
+  Site *topsite;
+  int right_of_site, above, fast;
+  double dxp, dyp, dxs, t1, t2, t3, yl;
+	
+  e = el->ELedge;
+  topsite = e->reg[1];
+  right_of_site = p->x > topsite->coord.x;
+  if(right_of_site && el->ELpm == le) return(1);
+  if(!right_of_site && el->ELpm == re) return (0);
+	
+  if (e->a == 1.0)
+    {	dyp = p->y - topsite->coord.y;
+    dxp = p->x - topsite->coord.x;
+    fast = 0;
+    if ((!right_of_site & (e->b<0.0)) | (right_of_site & (e->b>=0.0)) )
+      {	above = dyp>= e->b*dxp;	
+      fast = above;
+      }
+    else 
+      {	above = p->x + p->y*e->b > e-> c;
+      if(e->b<0.0) above = !above;
+      if (!above) fast = 1;
+      };
+    if (!fast)
+      {	dxs = topsite->coord.x - (e->reg[0])->coord.x;
+      above = e->b * (dxp*dxp - dyp*dyp) <
+	dxs*dyp*(1.0+2.0*dxp/dxs + e->b*e->b);
+      if(e->b<0.0) above = !above;
+      };
+    }
+  else  /*e->b==1.0 */
+    {	yl = e->c - e->a*p->x;
+    t1 = p->y - yl;
+    t2 = p->x - topsite->coord.x;
+    t3 = yl - topsite->coord.y;
+    above = t1*t1 > t2*t2 + t3*t3;
+    };
+  return (el->ELpm==le ? above : !above);
+}
+
+
+void VoronoiDiagramGenerator::endpoint(Edge *e,int lr,Site * s)
+{
+  e->ep[lr] = s;
+  ref(s);
+  if(e->ep[re-lr]== (Site *) NULL) 
+    return;
+
+  clip_line(e);
+
+  deref(e->reg[le]);
+  deref(e->reg[re]);
+  makefree((Freenode*)e, &efl);
+}
+
+
+double VoronoiDiagramGenerator::dist(Site *s,Site *t)
+{
+  double dx,dy;
+  dx = s->coord.x - t->coord.x;
+  dy = s->coord.y - t->coord.y;
+  return (double)(sqrt(dx*dx + dy*dy));
+}
+
+
+void VoronoiDiagramGenerator::makevertex(Site *v)
+{
+  v->sitenbr = nvertices;
+  nvertices += 1;
+  out_vertex(v);
+}
+
+
+void VoronoiDiagramGenerator::deref(Site *v)
+{
+  v->refcnt -= 1;
+  if (v->refcnt == 0 ) 
+    makefree((Freenode*)v, &sfl);
+}
+
+void VoronoiDiagramGenerator::ref(Site *v)
+{
+  v->refcnt += 1;
+}
+
+//push the HalfEdge into the ordered linked list of vertices
+void VoronoiDiagramGenerator::PQinsert(Halfedge *he,Site * v, double offset)
+{
+  Halfedge *last, *next;
+	
+  he->vertex = v;
+  ref(v);
+  he->ystar = (double)(v->coord.y + offset);
+  last = &PQhash[PQbucket(he)];
+  while ((next = last->PQnext) != (Halfedge *) NULL &&
+	 (he->ystar  > next->ystar  ||
+	  (he->ystar == next->ystar && v->coord.x > next->vertex->coord.x)))
+    {	
+      last = next;
+    };
+  he->PQnext = last->PQnext; 
+  last->PQnext = he;
+  PQcount += 1;
+}
+
+//remove the HalfEdge from the list of vertices 
+void VoronoiDiagramGenerator::PQdelete(Halfedge *he)
+{
+  Halfedge *last;
+	
+  if(he->vertex != (Site *) NULL)
+    {	
+      last = &PQhash[PQbucket(he)];
+      while (last->PQnext != he) 
+	last = last->PQnext;
+
+      last->PQnext = he->PQnext;
+      PQcount -= 1;
+      deref(he->vertex);
+      he->vertex = (Site *) NULL;
+    };
+}
+
+int VoronoiDiagramGenerator::PQbucket(Halfedge *he)
+{
+  int bucket;
+	
+  bucket = (int)((he->ystar - ymin)/deltay * PQhashsize);
+  if (bucket<0) bucket = 0;
+  if (bucket>=PQhashsize) bucket = PQhashsize-1 ;
+  if (bucket < PQmin) PQmin = bucket;
+  return(bucket);
+}
+
+
+
+int VoronoiDiagramGenerator::PQempty()
+{
+  return(PQcount==0);
+}
+
+
+Point VoronoiDiagramGenerator::PQ_min()
+{
+  Point answer;
+	
+  while(PQhash[PQmin].PQnext == (Halfedge *)NULL) {PQmin += 1;};
+  answer.x = PQhash[PQmin].PQnext->vertex->coord.x;
+  answer.y = PQhash[PQmin].PQnext->ystar;
+  return (answer);
+}
+
+Halfedge * VoronoiDiagramGenerator::PQextractmin()
+{
+  Halfedge *curr;
+	
+  curr = PQhash[PQmin].PQnext;
+  PQhash[PQmin].PQnext = curr->PQnext;
+  PQcount -= 1;
+  return(curr);
+}
+
+
+bool VoronoiDiagramGenerator::PQinitialize()
+{
+  int i; 
+	
+  PQcount = 0;
+  PQmin = 0;
+  PQhashsize = 4 * sqrt_nsites;
+  //PQhash = (Halfedge *) myalloc(PQhashsize * sizeof *PQhash);
+  PQhash = (Halfedge *) myalloc(PQhashsize * sizeof(Halfedge));
+
+  if(PQhash == 0)
+    return false;
+
+  for(i=0; i<PQhashsize; i+=1) PQhash[i].PQnext = (Halfedge *)NULL;
+
+  return true;
+}
+
+
+void VoronoiDiagramGenerator::freeinit(Freelist *fl,int size)
+{
+  fl->head = (Freenode *) NULL;
+  fl->nodesize = size;
+}
+
+char * VoronoiDiagramGenerator::getfree(Freelist *fl)
+{
+  int i; 
+  Freenode *t;
+
+  if(fl->head == (Freenode *) NULL)
+    {	
+      t =  (Freenode *) myalloc(sqrt_nsites * fl->nodesize);
+
+      if(t == 0)
+	return 0;
+		
+      currentMemoryBlock->next = new FreeNodeArrayList;
+      currentMemoryBlock = currentMemoryBlock->next;
+      currentMemoryBlock->memory = t;
+      currentMemoryBlock->next = 0;
+
+      for(i=0; i<sqrt_nsites; i+=1) 	
+	makefree((Freenode *)((char *)t+i*fl->nodesize), fl);		
+    };
+  t = fl->head;
+  fl->head = (fl->head)->nextfree;
+  return((char *)t);
+}
+
+
+
+void VoronoiDiagramGenerator::makefree(Freenode *curr,Freelist *fl)
+{
+  curr->nextfree = fl->head;
+  fl->head = curr;
+}
+
+void VoronoiDiagramGenerator::cleanup()
+{
+  if(sites != NULL){
+    free(sites);
+    sites = 0;
+  }
+
+  FreeNodeArrayList* current=NULL, *prev=NULL;
+
+  current = prev = allMemoryList;
+
+  while(current->next!=NULL){
+    prev = current;
+    current = current->next;
+    free(prev->memory);
+    delete prev;
+    prev = NULL;
+  }
+
+  if(current!=NULL){
+    if (current->memory!=NULL){
+      free(current->memory);
+    }
+    delete current;
+  }
+
+  allMemoryList = new FreeNodeArrayList;
+  allMemoryList->next = NULL;
+  allMemoryList->memory = NULL;
+  currentMemoryBlock = allMemoryList;
+
+  if (ELhash!=NULL)
+    free(ELhash);
+
+  if (PQhash!=NULL)
+    free(PQhash);
+}
+
+void VoronoiDiagramGenerator::cleanupEdges()
+{
+  GraphEdge* geCurrent = NULL, *gePrev = NULL;
+  geCurrent = gePrev = allEdges;
+
+  while(geCurrent!=NULL){
+    gePrev = geCurrent;
+    geCurrent = geCurrent->next;
+    delete gePrev;
+  }
+
+  allEdges = 0;
+
+}
+
+void VoronoiDiagramGenerator::pushGraphEdge(double x1, double y1, double x2, double y2,
+					    Site *s1, Site *s2)
+{
+  GraphEdge* newEdge = new GraphEdge;
+  newEdge->next = allEdges;
+  allEdges = newEdge;
+  newEdge->x1 = x1;
+  newEdge->y1 = y1;
+  newEdge->x2 = x2;
+  newEdge->y2 = y2;
+
+  newEdge->point1 = s1->sitenbr;
+  newEdge->point2 = s2->sitenbr;
+}
+
+
+char * VoronoiDiagramGenerator::myalloc(unsigned n)
+{
+  char *t=0;	
+  t=(char*)malloc(n);
+  total_alloc += n;
+  return(t);
+}
+
+
+/* for those who don't have Cherry's plot */
+/* #include <plot.h> */
+void VoronoiDiagramGenerator::openpl(){}
+void VoronoiDiagramGenerator::circle(double x, double y, double radius){}
+void VoronoiDiagramGenerator::range(double minX, double minY, double maxX, double maxY){}
+
+
+
+void VoronoiDiagramGenerator::out_bisector(Edge *e)
+{
+	
+
+}
+
+
+void VoronoiDiagramGenerator::out_ep(Edge *e)
+{
+	
+	
+}
+
+void VoronoiDiagramGenerator::out_vertex(Site *v)
+{
+	
+}
+
+
+void VoronoiDiagramGenerator::out_site(Site *s)
+{
+  if(!triangulate & plot & !debug)
+    circle (s->coord.x, s->coord.y, cradius);
+	
+}
+
+
+void VoronoiDiagramGenerator::out_triple(Site *s1, Site *s2,Site * s3)
+{
+	
+}
+
+
+
+void VoronoiDiagramGenerator::plotinit()
+{
+  double dx,dy,d;
+	
+  dy = ymax - ymin;
+  dx = xmax - xmin;
+  d = (double)(( dx > dy ? dx : dy) * 1.1);
+  pxmin = (double)(xmin - (d-dx)/2.0);
+  pxmax = (double)(xmax + (d-dx)/2.0);
+  pymin = (double)(ymin - (d-dy)/2.0);
+  pymax = (double)(ymax + (d-dy)/2.0);
+  cradius = (double)((pxmax - pxmin)/350.0);
+  openpl();
+  range(pxmin, pymin, pxmax, pymax);
+}
+
+
+void VoronoiDiagramGenerator::clip_line(Edge *e)
+{
+  Site *s1, *s2;
+  double x1=0,x2=0,y1=0,y2=0; //, temp = 0;
+
+  x1 = e->reg[0]->coord.x;
+  x2 = e->reg[1]->coord.x;
+  y1 = e->reg[0]->coord.y;
+  y2 = e->reg[1]->coord.y;
+
+  //if the distance between the two points this line was created from is less than 
+  //the square root of 2, then ignore it
+  //TODO improve/remove
+  //if(sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) < minDistanceBetweenSites)
+  //  {
+  //    return;
+  //  }
+  pxmin = borderMinX;
+  pxmax = borderMaxX;
+  pymin = borderMinY;
+  pymax = borderMaxY;
+
+  if(e->a == 1.0 && e ->b >= 0.0)
+    {	
+      s1 = e->ep[1];
+      s2 = e->ep[0];
+    }
+  else 
+    {
+      s1 = e->ep[0];
+      s2 = e->ep[1];
+    };
+	
+  if(e->a == 1.0)
+    {
+      y1 = pymin;
+      if (s1!=(Site *)NULL && s1->coord.y > pymin)
+	{
+	  y1 = s1->coord.y;
+	}
+      if(y1>pymax) 
+	{
+	  //	printf("\nClipped (1) y1 = %f to %f",y1,pymax);
+	  y1 = pymax;
+	  //return;
+	}
+      x1 = e->c - e->b * y1;
+      y2 = pymax;
+      if (s2!=(Site *)NULL && s2->coord.y < pymax) 
+	y2 = s2->coord.y;
+
+      if(y2<pymin) 
+	{
+	  //printf("\nClipped (2) y2 = %f to %f",y2,pymin);
+	  y2 = pymin;
+	  //return;
+	}
+      x2 = (e->c) - (e->b) * y2;
+      if (((x1> pxmax) & (x2>pxmax)) | ((x1<pxmin)&(x2<pxmin))) 
+	{
+	  //printf("\nClipLine jumping out(3), x1 = %f, pxmin = %f, pxmax = %f",x1,pxmin,pxmax);
+	  return;
+	}
+      if(x1> pxmax)
+	{	x1 = pxmax; y1 = (e->c - x1)/e->b;};
+      if(x1<pxmin)
+	{	x1 = pxmin; y1 = (e->c - x1)/e->b;};
+      if(x2>pxmax)
+	{	x2 = pxmax; y2 = (e->c - x2)/e->b;};
+      if(x2<pxmin)
+	{	x2 = pxmin; y2 = (e->c - x2)/e->b;};
+    }
+  else
+    {
+      x1 = pxmin;
+      if (s1!=(Site *)NULL && s1->coord.x > pxmin) 
+	x1 = s1->coord.x;
+      if(x1>pxmax) 
+	{
+	  //printf("\nClipped (3) x1 = %f to %f",x1,pxmin);
+	  //return;
+	  x1 = pxmax;
+	}
+      y1 = e->c - e->a * x1;
+      x2 = pxmax;
+      if (s2!=(Site *)NULL && s2->coord.x < pxmax) 
+	x2 = s2->coord.x;
+      if(x2<pxmin) 
+	{
+	  //printf("\nClipped (4) x2 = %f to %f",x2,pxmin);
+	  //return;
+	  x2 = pxmin;
+	}
+      y2 = e->c - e->a * x2;
+      if (((y1> pymax) & (y2>pymax)) | ((y1<pymin)&(y2<pymin))) 
+	{
+	  //printf("\nClipLine jumping out(6), y1 = %f, pymin = %f, pymax = %f",y2,pymin,pymax);
+	  return;
+	}
+      if(y1> pymax)
+	{	y1 = pymax; x1 = (e->c - y1)/e->a;};
+      if(y1<pymin)
+	{	y1 = pymin; x1 = (e->c - y1)/e->a;};
+      if(y2>pymax)
+	{	y2 = pymax; x2 = (e->c - y2)/e->a;};
+      if(y2<pymin)
+	{	y2 = pymin; x2 = (e->c - y2)/e->a;};
+    };
+	
+  //printf("\nPushing line (%f,%f,%f,%f)",x1,y1,x2,y2);
+  //fprintf(stdout, "Line with vertices (%f,%f) and (%f,%f)\n", 
+  //	e->reg[0]->coord.x, e->reg[1]->coord.x, e->reg[0]->coord.y, e->reg[1]->coord.y);
+  pushGraphEdge(x1,y1,x2,y2,e->reg[0],e->reg[1]);
+}
+
+
+/* implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
+   deltax, deltay (can all be estimates).
+   Performance suffers if they are wrong; better to make nsites,
+   deltax, and deltay too big than too small.  (?) */
+
+bool VoronoiDiagramGenerator::voronoi(int triangulate)
+{
+  Site *newsite, *bot, *top, *temp, *p;
+  Site *v;
+  Point newintstar;
+  int pm;
+  Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
+  Edge *e;
+	
+  PQinitialize();
+  bottomsite = nextone();
+  out_site(bottomsite);
+  bool retval = ELinitialize();
+
+  if(!retval)
+    return false;
+	
+  newsite = nextone();
+  while(1)
+    {
+
+      if(!PQempty()) 
+	newintstar = PQ_min();
+		
+      //if the lowest site has a smaller y value than the lowest vector intersection, process the site
+      //otherwise process the vector intersection		
+      if (newsite != (Site *)NULL){
+	volatile double local_newsite_coord_y = newsite->coord.y;
+	volatile double local_newintstar_y = newintstar.y;
+ 	if (PQempty() ||  local_newsite_coord_y < local_newintstar_y
+	    || ( local_newsite_coord_y == local_newintstar_y && newsite->coord.x < newintstar.x))
+	  {/* new site is smallest - this is a site event*/
+	    out_site(newsite);						//output the site
+	    lbnd = ELleftbnd(&(newsite->coord));				//get the first HalfEdge to the LEFT of the new site
+	    rbnd = ELright(lbnd);						//get the first HalfEdge to the RIGHT of the new site
+	    bot = rightreg(lbnd);						//if this halfedge has no edge, , bot = bottom site (whatever that is)
+	    e = bisect(bot, newsite);					//create a new edge that bisects 
+	    bisector = HEcreate(e, le);					//create a new HalfEdge, setting its ELpm field to 0			
+	    ELinsert(lbnd, bisector);					//insert this new bisector edge between the left and right vectors in a linked list	
+	    
+	    if ((p = intersect(lbnd, bisector)) != (Site *) NULL) 	//if the new bisector intersects with the left edge, remove the left edge's vertex, and put in the new one
+	      {	
+		PQdelete(lbnd);
+		PQinsert(lbnd, p, dist(p,newsite));
+	      };
+	    lbnd = bisector;						
+	    bisector = HEcreate(e, re);					//create a new HalfEdge, setting its ELpm field to 1
+	    ELinsert(lbnd, bisector);					//insert the new HE to the right of the original bisector earlier in the IF stmt
+	    
+	    if ((p = intersect(bisector, rbnd)) != (Site *) NULL)	//if this new bisector intersects with the
+	      {	
+		PQinsert(bisector, p, dist(p,newsite));			//push the HE into the ordered linked list of vertices
+	      };
+	    newsite = nextone();	
+	  }
+	else if (!PQempty()) /* intersection is smallest - this is a vector event */			
+	  {	
+	    lbnd = PQextractmin();						//pop the HalfEdge with the lowest vector off the ordered list of vectors				
+	    llbnd = ELleft(lbnd);						//get the HalfEdge to the left of the above HE
+	    rbnd = ELright(lbnd);						//get the HalfEdge to the right of the above HE
+	    rrbnd = ELright(rbnd);						//get the HalfEdge to the right of the HE to the right of the lowest HE 
+	    bot = leftreg(lbnd);						//get the Site to the left of the left HE which it bisects
+	    top = rightreg(rbnd);						//get the Site to the right of the right HE which it bisects
+	    
+	    out_triple(bot, top, rightreg(lbnd));		//output the triple of sites, stating that a circle goes through them
+	    
+	    v = lbnd->vertex;						//get the vertex that caused this event
+	    makevertex(v);							//set the vertex number - couldn't do this earlier since we didn't know when it would be processed
+	    endpoint(lbnd->ELedge,lbnd->ELpm,v);	//set the endpoint of the left HalfEdge to be this vector
+	    endpoint(rbnd->ELedge,rbnd->ELpm,v);	//set the endpoint of the right HalfEdge to be this vector
+	    ELdelete(lbnd);							//mark the lowest HE for deletion - can't delete yet because there might be pointers to it in Hash Map	
+	    PQdelete(rbnd);							//remove all vertex events to do with the  right HE
+	    ELdelete(rbnd);							//mark the right HE for deletion - can't delete yet because there might be pointers to it in Hash Map	
+	    pm = le;								//set the pm variable to zero
+	    
+	    if (bot->coord.y > top->coord.y)		//if the site to the left of the event is higher than the Site
+	      {										//to the right of it, then swap them and set the 'pm' variable to 1
+		temp = bot; 
+		bot = top; 
+		top = temp; 
+		pm = re;
+	      }
+	    e = bisect(bot, top);					//create an Edge (or line) that is between the two Sites. This creates
+	    //the formula of the line, and assigns a line number to it
+	    bisector = HEcreate(e, pm);				//create a HE from the Edge 'e', and make it point to that edge with its ELedge field
+	    ELinsert(llbnd, bisector);				//insert the new bisector to the right of the left HE
+	    endpoint(e, re-pm, v);					//set one endpoint to the new edge to be the vector point 'v'.
+	    //If the site to the left of this bisector is higher than the right
+	    //Site, then this endpoint is put in position 0; otherwise in pos 1
+	    deref(v);								//delete the vector 'v'
+	    
+	    //if left HE and the new bisector don't intersect, then delete the left HE, and reinsert it 
+	    if((p = intersect(llbnd, bisector)) != (Site *) NULL)
+	      {	
+		PQdelete(llbnd);
+		PQinsert(llbnd, p, dist(p,bot));
+	      };
+	    
+	    //if right HE and the new bisector don't intersect, then reinsert it 
+	    if ((p = intersect(bisector, rrbnd)) != (Site *) NULL)
+	      {	
+		PQinsert(bisector, p, dist(p,bot));
+	      };
+	  }
+      } else break;
+    };
+
+	
+
+
+  for(lbnd=ELright(ELleftend); lbnd != ELrightend; lbnd=ELright(lbnd))
+    {	
+      e = lbnd->ELedge;
+
+      clip_line(e);
+    };
+
+  //cleanup();
+
+  return true;
+	
+}
+
+
+int scomp(const void *p1,const void *p2)
+{
+  Point *s1 = (Point*)p1, *s2=(Point*)p2;
+  if(s1->y < s2->y) return(-1);
+  if(s1->y > s2->y) return(1);
+  if(s1->x < s2->x) return(-1);
+  if(s1->x > s2->x) return(1);
+  return(0);
+}
+
+/* return a single in-storage site */
+Site * VoronoiDiagramGenerator::nextone()
+{
+  Site *s;
+  if(siteidx < nsites)
+    {	
+      s = &sites[siteidx];
+      siteidx += 1;
+      return(s);
+    }
+  else	
+    return( (Site *)NULL);
+}
+
+FASTJET_END_NAMESPACE
Index: /trunk/data/DataCardDet.dat
===================================================================
--- /trunk/data/DataCardDet.dat	(revision 10)
+++ /trunk/data/DataCardDet.dat	(revision 11)
@@ -54,3 +54,3 @@
 #DeltaR cone definition
 CONERADIUS       	0.7
-JETALGO                 1               // 1 for Cone algorithm, 2 for MidPoint algorithm
+JETALGO                 3               // 1 for Cone algorithm, 2 for MidPoint algorithm, 3 for SIScone algorithm, 4 for kt algorithm
Index: /trunk/genMakefile.tcl
===================================================================
--- /trunk/genMakefile.tcl	(revision 10)
+++ /trunk/genMakefile.tcl	(revision 11)
@@ -126,5 +126,5 @@
   global prefix suffix objSuf exeSuf
    
-  set executable [glob -nocomplain {Delphes.cpp} {Resolutions.cpp}]
+  set executable [glob -nocomplain {Delphes.cpp} ]
                                 
   set exeFiles {}
@@ -232,7 +232,7 @@
 executableDeps {*.cpp} 
 
-dictDeps {DICT} {Utilities/ExRootAnalysis/src/*LinkDef.h} {src/*LinkDef.h}
-
-sourceDeps {SOURCE} {src/*.cc} {Utilities/ExRootAnalysis/src/*.cc} {Utilities/Hector/src/*.cc} {Utilities/CDFCones/src/*cc} 
+dictDeps {DICT} {Utilities/ExRootAnalysis/src/*LinkDef.h}
+
+sourceDeps {SOURCE} {src/*.cc} {Utilities/ExRootAnalysis/src/*.cc} {Utilities/Hector/src/*.cc} {Utilities/CDFCones/src/*cc} {Utilities/Fastjet/src/*.cc} {Utilities/Fastjet/plugins/CDFCones/*.cc} {Utilities/Fastjet/plugins/CDFCones/src/*.cc} {Utilities/Fastjet/plugins/SISCone/*.cc} {Utilities/Fastjet/plugins/SISCone/src/*.cc}
 
 stdhepDeps
Index: /trunk/interface/HEPEVTConverter.h
===================================================================
--- /trunk/interface/HEPEVTConverter.h	(revision 10)
+++ /trunk/interface/HEPEVTConverter.h	(revision 11)
@@ -27,5 +27,5 @@
 #include "Utilities/ExRootAnalysis/interface/BlockClasses.h"
 #include "Utilities/ExRootAnalysis/interface/TSimpleArray.h"
-#include "Utilities/CDFCones/interface/PhysicsTower.h"
+//#include "Utilities/CDFCones/interface/PhysicsTower.h"
 #include "interface/DataConverter.h"
 using namespace std;
Index: /trunk/interface/STDHEPConverter.h
===================================================================
--- /trunk/interface/STDHEPConverter.h	(revision 10)
+++ /trunk/interface/STDHEPConverter.h	(revision 11)
@@ -27,5 +27,5 @@
 #include "Utilities/ExRootAnalysis/interface/BlockClasses.h"
 #include "Utilities/ExRootAnalysis/interface/TSimpleArray.h"
-#include "Utilities/CDFCones/interface/PhysicsTower.h"
+//#include "Utilities/CDFCones/interface/PhysicsTower.h"
 #include "Utilities/ExRootAnalysis/interface/LHEF.h"
 
Index: /trunk/interface/SmearUtil.h
===================================================================
--- /trunk/interface/SmearUtil.h	(revision 10)
+++ /trunk/interface/SmearUtil.h	(revision 11)
@@ -22,5 +22,5 @@
 #include "Utilities/ExRootAnalysis/interface/TSimpleArray.h"
 
-#include "Utilities/CDFCones/interface/PhysicsTower.h"
+#include "Utilities/Fastjet/plugins/CDFCones/interface/PhysicsTower.hh"
 using namespace std;
 
Index: /trunk/src/SmearUtil.cc
===================================================================
--- /trunk/src/SmearUtil.cc	(revision 10)
+++ /trunk/src/SmearUtil.cc	(revision 11)
@@ -76,5 +76,5 @@
 
 CONERADIUS   = 0.7; 	// generic jet radius ; not for tau's !!!
-JETALGO      =   1;
+JETALGO      =   1;     // 1 for Cone algorithm, 2 for MidPoint algorithm, 3 for SIScone algorithm, 4 for kt algorithm
 // Define Cone algorithm.
 C_SEEDTHRESHOLD     = 1.0;
