Print

Print


Commit in lcsim/src/org/lcsim/recon/cluster on MAIN
cheat/CheatCluster.java+23added 1.1
     /CreateCheatClusters.java+59added 1.1
     /ClusterCheater.java+8-551.2 -> 1.3
fixedcone/CreateFCClusters.java+295added 1.1
         /FixedConeClusterer.java+7-2511.3 -> 1.4
nn/CreateNNClusters.java+90added 1.1
  /NearestNeighborCluster.java+2-21.4 -> 1.5
  /NearestNeighborClusterer.java+5-221.5 -> 1.6
util/ClusterESort.java+31added 1.1
    /FCClusterPropertyCalculator.java+330added 1.1
    /CalorimeterCluster.java+1-11.3 -> 1.4
    /BasicCluster.java+52-271.1 -> 1.2
    /DefaultClusterPropertyCalculator.java+10-11.1 -> 1.2
    /TensorClusterPropertyCalculator.java+71.1 -> 1.2
+920-359
6 added + 8 modified, total 14 files
Reorganization of Clusters and clustering

lcsim/src/org/lcsim/recon/cluster/cheat
CheatCluster.java added at 1.1
diff -N CheatCluster.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CheatCluster.java	8 Jul 2005 17:15:05 -0000	1.1
@@ -0,0 +1,23 @@
+package org.lcsim.recon.cluster.cheat;
+
+import org.lcsim.event.Cluster;
+import org.lcsim.event.MCParticle;
+import org.lcsim.recon.cluster.util.BasicCluster;
+
+
+/**
+ * Add the MCParticle to BasicCluster
+ */
+
+public class CheatCluster extends BasicCluster
+{
+   private MCParticle particle;
+   CheatCluster(MCParticle particle)
+   {
+      this.particle = particle;
+   }
+   MCParticle getMCParticle()
+   {
+      return particle;
+   }
+}

lcsim/src/org/lcsim/recon/cluster/cheat
CreateCheatClusters.java added at 1.1
diff -N CreateCheatClusters.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CreateCheatClusters.java	8 Jul 2005 17:15:05 -0000	1.1
@@ -0,0 +1,59 @@
+package org.lcsim.recon.cluster.cheat;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.recon.cluster.util.BasicCluster;
+
+
+/**
+ * The Cluster cheater works by finding perfectly reconstructed clusters
+ * based by looking at the MC truth information associated with each hit.
+ *
+ * To simplify the coding for now, if more than one MC particle is associated with a
+ * single hit, the entire hit is associated with the cluster belonging to the MC
+ * particle that contributed the most energy to the hit. Note that there is currently
+ * no attempt to merge clusters that would in fact be impossible to resolve.
+ */
+
+public class CreateCheatClusters
+{
+   
+   public Map<MCParticle, CheatCluster> findClusters(List<SimCalorimeterHit> hits)
+   {
+      Map<MCParticle,CheatCluster> result = new HashMap<MCParticle,CheatCluster>();
+      for (SimCalorimeterHit hit : hits)
+      {        
+         double eMax = hit.getContributedEnergy(0);
+         MCParticle pMax = hit.getMCParticle(0);
+         for (int i=1; i<hit.getMCParticleCount(); i++)
+         {
+            if (hit.getContributedEnergy(i) > eMax) pMax = hit.getMCParticle(i);
+         }
+         CheatCluster cc = result.get(pMax);
+         if (cc == null) result.put(pMax,cc = new CheatCluster(pMax));
+         cc.addHit(hit);        
+      }
+      return result;
+   }
+   public Map<MCParticle, CheatCluster> findRefinedClusters(List<List<CheatCluster>> collections)
+   {
+      Map<MCParticle, CheatCluster> result = new HashMap<MCParticle,CheatCluster>();
+      for (List<CheatCluster> clusters : collections)
+      {
+         for (CheatCluster cluster : clusters)
+         {
+            MCParticle p = cluster.getMCParticle();
+            CheatCluster rc = result.get(p);
+            if (rc == null) result.put(p,rc = new CheatCluster(p));
+            rc.addCluster(cluster);
+         }
+      }
+      return result;
+   }
+   
+}

lcsim/src/org/lcsim/recon/cluster/cheat
ClusterCheater.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- ClusterCheater.java	16 Feb 2005 07:28:05 -0000	1.2
+++ ClusterCheater.java	8 Jul 2005 17:15:05 -0000	1.3
@@ -8,55 +8,20 @@
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.MCParticle;
 import org.lcsim.event.SimCalorimeterHit;
-import org.lcsim.recon.cluster.util.HitsCluster;
-import org.lcsim.recon.cluster.util.RefinedCluster;
+import org.lcsim.recon.cluster.util.BasicCluster;
 import org.lcsim.util.Driver;
 
 
 /**
- * The Cluster cheater works by finding perfectly reconstructed clusters
- * based by looking at the MC truth information associated with each hit.
- *
- * To simplify the coding for now, if more than one MC particle is associated with a
- * single hit, the entire hit is associated with the cluster belonging to the MC
- * particle that contributed the most energy to the hit. Note that there is currently
- * no attempt to merge clusters that would in fact be impossible to resolve.
+ * Driver to create and write CheatClusters to the event
  */
 
 public class ClusterCheater extends Driver
 {
-   
-   private Map<MCParticle, CheatCluster> findClusters(List<SimCalorimeterHit> hits)
-   {
-      Map<MCParticle,CheatCluster> result = new HashMap<MCParticle,CheatCluster>();
-      for (SimCalorimeterHit hit : hits)
-      {        
-         double eMax = hit.getContributedEnergy(0);
-         MCParticle pMax = hit.getMCParticle(0);
-         for (int i=1; i<hit.getMCParticleCount(); i++)
-         {
-            if (hit.getContributedEnergy(i) > eMax) pMax = hit.getMCParticle(i);
-         }
-         CheatCluster cc = result.get(pMax);
-         if (cc == null) result.put(pMax,cc = new CheatCluster(pMax));
-         cc.addHit(hit);        
-      }
-      return result;
-   }
-   private Map<MCParticle, RefinedCluster> findRefinedClusters(List<List<CheatCluster>> collections)
+   CreateCheatClusters ccc;
+   public ClusterCheater()
    {
-      Map<MCParticle, RefinedCluster> result = new HashMap<MCParticle,RefinedCluster>();
-      for (List<CheatCluster> clusters : collections)
-      {
-         for (CheatCluster cluster : clusters)
-         {
-            MCParticle p = cluster.getMCParticle();
-            RefinedCluster rc = result.get(p);
-            if (rc == null) result.put(p,rc = new RefinedCluster());
-            rc.add(cluster);
-         }
-      }
-      return result;
+	  ccc = new CreateCheatClusters();
    }
    
    public void process(EventHeader event)
@@ -66,7 +31,7 @@
       List<List<SimCalorimeterHit>> collections = event.get(SimCalorimeterHit.class);
       for (List<SimCalorimeterHit> collection : collections)
       {
-         Map<MCParticle,CheatCluster> result = findClusters(collection);
+         Map<MCParticle,CheatCluster> result = ccc.findClusters(collection);
          String name = event.getMetaData(collection).getName();
          if (result.size() > 0) event.put(name+"Clusters",new ArrayList(result.values()));
       }
@@ -74,19 +39,7 @@
       // Then look for refined clusters combining hits from all collections
       
       List<List<CheatCluster>> clusters = event.get(CheatCluster.class);
-      Map<MCParticle, RefinedCluster> refined = findRefinedClusters(clusters);
+      Map<MCParticle, CheatCluster> refined = ccc.findRefinedClusters(clusters);
       if (refined.size() > 0) event.put("RefinedClusters",new ArrayList(refined.values()));
    }
-   private static class CheatCluster extends HitsCluster
-   {
-      private MCParticle particle;
-      CheatCluster(MCParticle particle)
-      {
-         this.particle = particle;
-      }
-      MCParticle getMCParticle()
-      {
-         return particle;
-      }
-   }
-}
\ No newline at end of file
+}

lcsim/src/org/lcsim/recon/cluster/fixedcone
CreateFCClusters.java added at 1.1
diff -N CreateFCClusters.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CreateFCClusters.java	8 Jul 2005 17:15:06 -0000	1.1
@@ -0,0 +1,295 @@
+package org.lcsim.recon.cluster.fixedcone;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.event.util.CalorimeterHitEsort;
+import org.lcsim.geometry.CalorimeterIDDecoder;
+import org.lcsim.recon.cluster.util.*;
+import org.lcsim.util.Driver;
+import org.lcsim.util.fourvec.Lorentz4Vector;
+import org.lcsim.util.fourvec.Momentum4Vector;
+
+/**
+ * FixedConeClusterer implements a
+ * <font face="symbol">q-f </font> cone clustering algorithm
+ * that assigns all neighboring hits to the same cluster if they fall
+ * within a radius R of the cluster axis. The axis is originally defined
+ * by a seed cell, and is iteratively updated as cells are added.
+ * This version of the ClusterBuilder splits overlapping clusters
+ * by assigning cells in the overlap region to the nearest cluster axis.
+ *
+ * @author Norman A. Graf
+ * @version 1.0
+ */
+
+public class CreateFCClusters 
+{
+    private double _radius;
+    private double _Eseed;
+    private double _Emin;
+    private int _numLayers;
+    private double _samplingFraction;
+    private double[] _layerEnergy;
+    
+    CalorimeterIDDecoder _decoder;
+    
+    private static final double PI=Math.PI;
+    private static final double TWOPI = 2.*PI;
+	public FCClusterPropertyCalculator cpc;
+    
+    /**
+     * Constructor
+     *
+     * @param   radius The cone radius in <font face="symbol">q-f </font> space
+     * @param   seed   The minimum energy for a cone seed cell (in GeV)
+     * @param   minE   The minimum energy for a cluster (in GeV)
+     */
+    public CreateFCClusters(double radius, double seed, double minE)
+    {
+        _radius = radius;
+        // overwrite later with sampling fraction correction
+        _Eseed = seed;
+        _Emin = minE;
+    }
+	public void setRadius(double radius)
+	{
+		_radius = radius;
+	}
+	public void setSeed(double seed)
+	{
+		_Eseed = seed;
+	}
+	public void setMinE(double minE)
+	{
+		_Emin = minE;
+	}
+    
+    
+    /**
+     * Make clusters from the input list
+     */
+    public List<BasicCluster> makeClusters(List<CalorimeterHit> in, CalorimeterIDDecoder decoder)
+    {
+        List<BasicCluster> out = new ArrayList<BasicCluster>();
+		cpc = new FCClusterPropertyCalculator(decoder);
+        
+        double rsquared = _radius*_radius;
+        // sort the vector in descending energy for efficiency
+        // this starts with the highest energy seeds.
+        Collections.sort(in, new CalorimeterHitEsort());
+        
+        int nclus = 0;
+        int size = in.size();
+        boolean[] used = new boolean[size];
+        //   outer loop finds a seed
+        for(int i =0; i<size; ++i)
+        {
+            if (!used[i])
+            {
+                CalorimeterHit p = in.get(i);
+                if (p.getEnergy()>_Eseed)
+                {
+                    decoder.setID(p.getCellID());
+                    double cellE = p.getEnergy();
+                    double px = cellE*Math.cos(decoder.getPhi())*Math.sin(decoder.getTheta());
+                    double py = cellE*Math.sin(decoder.getPhi())*Math.sin(decoder.getTheta());
+                    double pz = cellE*Math.cos(decoder.getTheta());
+                    Lorentz4Vector sum = new Momentum4Vector(px,py,pz,cellE);
+                    double phiseed=sum.phi();
+                    double thetaseed=sum.theta();
+                    
+                    // constituent cells
+                    List<CalorimeterHit> members = new ArrayList<CalorimeterHit>();
+                    members.add(p);
+                    // inner loop adds neighboring cells to seed
+                    
+                    for (int j = i+1; j<size; ++j)
+                    {
+                        //                        if (in.get(j)!=null)
+                        if(!used[j])
+                        {
+                            CalorimeterHit p2 = in.get(j);
+                            decoder.setID(p2.getCellID());
+                            double phi = decoder.getPhi();
+                            double theta=decoder.getTheta();
+                            double dphi=phi-phiseed;
+                            
+                            if(dphi<-PI) dphi+=TWOPI;
+                            if(dphi>PI) dphi-=TWOPI;
+                            double dtheta = theta-thetaseed;
+                            double R2=dphi*dphi+dtheta*dtheta;
+                            if(R2< rsquared)
+                            {
+                                //  particle within cone
+                                cellE = p2.getEnergy();
+                                px = cellE*Math.cos(decoder.getPhi())*Math.sin(decoder.getTheta());
+                                py = cellE*Math.sin(decoder.getPhi())*Math.sin(decoder.getTheta());
+                                pz = cellE*Math.cos(decoder.getTheta());
+                                sum.plusEquals(new Momentum4Vector(px, py, pz, cellE));
+                                members.add(p2);
+                                // tag this element so we don't reuse it
+                                used[j]=true;
+                                
+                                //   recalculate cone center
+                                phiseed=sum.phi();
+                                thetaseed=sum.theta();
+                            }
+                        }
+                    }// end of inner loop
+                    
+                    
+                    // if energy of cluster is large enough add it to the list
+                    if(sum.E()>_Emin)
+                    {
+                        BasicCluster clus = new BasicCluster();
+						clus.setPropertyCalculator(cpc);
+                        for(CalorimeterHit hit : members)
+                        {
+                            clus.addHit(hit);
+                        }
+                        out.add(clus);
+                        nclus++;
+                    }
+                    
+                }
+            }// end of outer loop
+        }
+
+        if (nclus>1)
+        {
+            // sort the clusters in descending energy
+            Collections.sort(out, new ClusterESort());
+            // loop over the found clusters and look for overlaps
+            // i.e distance between clusters is less than 2*R
+            for(int i=0; i<out.size();++i  )
+            {
+                for(int j=i+1; j<out.size(); ++j)
+                {
+                    double dTheta = dTheta((BasicCluster)out.get(i), (BasicCluster)out.get(j));
+                    if (dTheta<2*_radius)
+                    {
+//                        resolve((BasicCluster)out.get(i), (BasicCluster)out.get(j));
+                    }
+                }
+            }
+        }
+
+//        System.out.println("found "+out.size()+ " clusters");
+        return out;
+    }
+    
+    
+    /**
+     * Calculate the angle between two Clusters
+     *
+     * @param   c1  First Cluster
+     * @param   c2  Second Cluster
+     * @return     The angle between the two clusters
+     */
+    
+    public double dTheta(BasicCluster c1, BasicCluster c2)
+    {
+		cpc.calculateProperties(c1.getCalorimeterHits());
+        Lorentz4Vector v1 = cpc.vector();
+		cpc.calculateProperties(c2.getCalorimeterHits());
+		Lorentz4Vector v2 = cpc.vector();
+        double costheta = (v1.vec3dot(v2))/(v1.p()*v2.p());
+        return Math.acos(costheta);
+    }
+     
+    /**
+     * Given two overlapping clusters, assign cells to nearest axis.
+     * The cluster axes are <em> not </em> iterated.
+     * Cluster quantities are recalculated after the split.
+     *
+     * @param   c1 First Cluster
+     * @param   c2 Second Cluster
+     */
+    
+    public void resolve(BasicCluster c1, BasicCluster c2)
+    {
+        // do not recalculate cluster axis until all reshuffling is done
+        // do not want the cones to shift
+        // this behavior may change in the future
+     
+		cpc.calculateProperties(c1.getCalorimeterHits());
+		Lorentz4Vector v1 = cpc.vector();
+        double phi1 = v1.phi();
+        double theta1 = v1.theta();
+		cpc.calculateProperties(c2.getCalorimeterHits());
+		Lorentz4Vector v2 = cpc.vector();
+        double phi2 = v2.phi();
+        double theta2 = v2.theta();
+        List<CalorimeterHit> cells1 = c1.getCalorimeterHits();
+        List<CalorimeterHit> cells2 = c2.getCalorimeterHits();
+        int size2 = cells2.size();
+     
+        List<CalorimeterHit> tmp = new ArrayList<CalorimeterHit>();
+        // loop over cells in first cluster...
+        for(int i=0; i<cells1.size(); ++i)
+        {
+            CalorimeterHit p2 = (CalorimeterHit) cells1.get(i);
+            _decoder.setID(p2.getCellID());
+            double phi = _decoder.getPhi();
+            double theta = _decoder.getTheta();
+            //distance to cluster 1
+            double dphi1=phi-phi1;
+            if(dphi1<-PI) dphi1+=TWOPI;
+            if(dphi1>PI) dphi1-=TWOPI;
+            double dtheta1 = theta-theta1;
+            double R1=dphi1*dphi1+(dtheta1)*(dtheta1);
+            // distance to cluster 2
+            double dphi2=phi-phi2;
+            if(dphi2<-PI) dphi2+=TWOPI;
+            if(dphi2>PI) dphi2-=TWOPI;
+            double dtheta2 = theta-theta2;
+            double R2=dphi2*dphi2+(dtheta2)*(dtheta2);
+     
+            if (R2<R1)
+            {
+				c1.removeHit(p2);
+				c2.addHit(p2);
+            }
+        }
+        tmp.clear();
+        // repeat for cluster 2
+        // only loop over cells in original cluster
+        for(int i=0; i<size2; ++i)
+        {
+            CalorimeterHit p2 = (CalorimeterHit) cells2.get(i);
+            _decoder.setID(p2.getCellID());
+            double phi = _decoder.getPhi();
+            double theta = _decoder.getTheta();
+            //distance to cluster 1
+            double dphi1=phi-phi1;
+            if(dphi1<-PI) dphi1+=TWOPI;
+            if(dphi1>PI) dphi1-=TWOPI;
+            double dtheta1 = theta-theta1;
+            double R1=dphi1*dphi1+(dtheta1)*(dtheta1);
+            // distance to cluster 2
+            double dphi2=phi-phi2;
+            if(dphi2<-PI) dphi2+=TWOPI;
+            if(dphi2>PI) dphi2-=TWOPI;
+            double dtheta2 = theta-theta2;
+            double R2=dphi2*dphi2+(dtheta2)*(dtheta2);
+     
+            if (R1<R2)
+            {
+				c2.removeHit(p2);
+				c1.addHit(p2);
+            }
+        }
+    }
+     
+    
+    public String toString()
+    {
+        return "FixedConeClusterer with radius "+_radius+" seed Energy "+_Eseed+" minimum energy "+_Emin;
+    }
+}

lcsim/src/org/lcsim/recon/cluster/fixedcone
FixedConeClusterer.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- FixedConeClusterer.java	15 Mar 2005 05:14:09 -0000	1.3
+++ FixedConeClusterer.java	8 Jul 2005 17:15:06 -0000	1.4
@@ -10,8 +10,7 @@
 import org.lcsim.event.SimCalorimeterHit;
 import org.lcsim.event.util.CalorimeterHitEsort;
 import org.lcsim.geometry.CalorimeterIDDecoder;
-import org.lcsim.recon.cluster.util.CalorimeterCluster;
-import org.lcsim.recon.cluster.util.HitsClusterESort;
+import org.lcsim.recon.cluster.util.*;
 import org.lcsim.util.Driver;
 import org.lcsim.util.fourvec.Lorentz4Vector;
 import org.lcsim.util.fourvec.Momentum4Vector;
@@ -37,6 +36,7 @@
     private int _numLayers;
     private double _samplingFraction;
     private double[] _layerEnergy;
+	private CreateFCClusters clusterer;
     
     CalorimeterIDDecoder _decoder;
     
@@ -56,7 +56,8 @@
         // overwrite later with sampling fraction correction
         _Eseed = seed;
         _Emin = minE;
-    }
+		clusterer = new CreateFCClusters(_radius, _Eseed, _Emin);
+	}
     
     
     /**
@@ -66,261 +67,16 @@
      */
     public void process(EventHeader event)
     {
-        List<SimCalorimeterHit> collection = event.get(SimCalorimeterHit.class,"EcalBarrHits");
+        List<CalorimeterHit> collection = event.get(CalorimeterHit.class,"EcalBarrHits");
         _decoder = (CalorimeterIDDecoder) event.getMetaData(collection).getIDDecoder();
 //        System.out.println(_decoder);
-        List clusters;
+        List<BasicCluster> clusters = clusterer.makeClusters(collection,_decoder);
         
-        // create a map of cells keyed on their index
-        Map<Long, CalorimeterHit> hitmap = new HashMap<Long, CalorimeterHit>();
-        for (SimCalorimeterHit hit : collection)
-        {
-            long id = hit.getCellID();
-            hitmap.put(id, hit);
-            _decoder.setID(id);
-            //            System.out.println(id+" "+decoder.getTheta()+ " "+decoder.getPhi()+ " "+decoder.getLayer());
-        }
-//        System.out.println("Found "+hitmap.size()+" hit cells in this event");
-        clusters = cluster(collection, _decoder);
         String name = event.getMetaData(collection).getName();
-        if (clusters.size() > 0) event.put(name+"NNClusters",clusters);
+        if (clusters.size() > 0) event.put(name+"FCClusters",clusters);
         
     }
    
-    /**
-     * Takes a list of CalorimeterHits, clusters them, and returns a list of
-     * CalorimeterClusters
-     *
-     * @param   in  A collection of CalorimeterHits
-     * @return  List of found CalorimeterClusters
-     */
-    
-    public List cluster(List<? extends CalorimeterHit> in, CalorimeterIDDecoder decoder)
-    {
-        List out = new ArrayList();
-        
-        double rsquared = _radius*_radius;
-        // sort the vector in descending energy for efficiency
-        // this starts with the highest energy seeds.
-        Collections.sort(in, new CalorimeterHitEsort());
-        
-        int nclus = 0;
-        int size = in.size();
-        boolean[] used = new boolean[size];
-        //   outer loop finds a seed
-        for(int i =0; i<size; ++i)
-        {
-            if (!used[i])
-            {
-                CalorimeterHit p = in.get(i);
-                if (p.getEnergy()>_Eseed)
-                {
-                    decoder.setID(p.getCellID());
-                    double cellE = p.getEnergy();
-                    double px = cellE*Math.cos(decoder.getPhi())*Math.sin(decoder.getTheta());
-                    double py = cellE*Math.sin(decoder.getPhi())*Math.sin(decoder.getTheta());
-                    double pz = cellE*Math.cos(decoder.getTheta());
-                    Lorentz4Vector sum = new Momentum4Vector(px,py,pz,cellE);
-                    double phiseed=sum.phi();
-                    double thetaseed=sum.theta();
-                    
-                    // constituent cells
-                    List<CalorimeterHit> members = new ArrayList<CalorimeterHit>();
-                    members.add(p);
-                    // inner loop adds neighboring cells to seed
-                    
-                    for (int j = i+1; j<size; ++j)
-                    {
-                        //                        if (in.get(j)!=null)
-                        if(!used[j])
-                        {
-                            CalorimeterHit p2 = in.get(j);
-                            decoder.setID(p2.getCellID());
-                            double phi = decoder.getPhi();
-                            double theta=decoder.getTheta();
-                            double dphi=phi-phiseed;
-                            
-                            if(dphi<-PI) dphi+=TWOPI;
-                            if(dphi>PI) dphi-=TWOPI;
-                            double dtheta = theta-thetaseed;
-                            double R2=dphi*dphi+dtheta*dtheta;
-                            if(R2< rsquared)
-                            {
-                                //  particle within cone
-                                cellE = p2.getEnergy();
-                                px = cellE*Math.cos(decoder.getPhi())*Math.sin(decoder.getTheta());
-                                py = cellE*Math.sin(decoder.getPhi())*Math.sin(decoder.getTheta());
-                                pz = cellE*Math.cos(decoder.getTheta());
-                                sum.plusEquals(new Momentum4Vector(px, py, pz, cellE));
-                                members.add(p2);
-                                // tag this element so we don't reuse it
-                                used[j]=true;
-                                
-                                //   recalculate cone center
-                                phiseed=sum.phi();
-                                thetaseed=sum.theta();
-                            }
-                        }
-                    }// end of inner loop
-                    
-                    
-                    // if energy of cluster is large enough add it to the list
-                    if(sum.E()>_Emin)
-                    {
-                        //                   HitsCluster clus = new HitsCluster(decoder,sum,members,_numLayers,_samplingFraction);
-                        CalorimeterCluster clus = new CalorimeterCluster(decoder,sum, members,30,1.);
-                        for(CalorimeterHit hit : members)
-                        {
-                            clus.addHit(hit);
-                        }
-                        out.add(clus);
-                        nclus++;
-                    }
-                    
-                }
-            }// end of outer loop
-        }
-
-        if (nclus>1)
-        {
-            // sort the clusters in descending energy
-            Collections.sort(out, new HitsClusterESort());
-            // loop over the found clusters and look for overlaps
-            // i.e distance between clusters is less than 2*R
-            for(int i=0; i<out.size();++i  )
-            {
-                for(int j=i+1; j<out.size(); ++j)
-                {
-                    double dTheta = dTheta((CalorimeterCluster)out.get(i), (CalorimeterCluster)out.get(j));
-                    if (dTheta<2*_radius)
-                    {
-//                        resolve((CalorimeterCluster)out.get(i), (CalorimeterCluster)out.get(j));
-                    }
-                }
-            }
-        }
-
-//        System.out.println("found "+out.size()+ " clusters");
-        return out;
-    }
-    
-    
-    /**
-     * Calculate the angle between two CalorimeterClusters
-     *
-     * @param   c1  First CalorimeterCluster
-     * @param   c2  Second CalorimeterCluster
-     * @return     The angle between the two clusters
-     */
-    
-    public double dTheta(CalorimeterCluster c1, CalorimeterCluster c2)
-    {
-        Lorentz4Vector v1 = c1.vector();
-        Lorentz4Vector v2 = c2.vector();
-        double costheta = (v1.vec3dot(v2))/(v1.p()*v2.p());
-        return Math.acos(costheta);
-    }
-     
-    /**
-     * Given two overlapping clusters, assign cells to nearest axis.
-     * The cluster axes are <em> not </em> iterated.
-     * Cluster quantities are recalculated after the split.
-     *
-     * @param   c1 First CalorimeterCluster
-     * @param   c2 Second CalorimeterCluster
-     */
-    
-    public void resolve(CalorimeterCluster c1, CalorimeterCluster c2)
-    {
-        // do not recalculate cluster axis until all reshuffling is done
-        // do not want the cones to shift
-        // this behavior may change in the future
-     
-        Lorentz4Vector v1 = c1.vector();
-        double phi1 = v1.phi();
-        double theta1 = v1.theta();
-        Lorentz4Vector v2 = c2.vector();
-        double phi2 = v2.phi();
-        double theta2 = v2.theta();
-        List<CalorimeterHit> cells1 = c1.cells();
-        List<CalorimeterHit> cells2 = c2.cells();
-        int size2 = cells2.size();
-     
-        List<CalorimeterHit> tmp = new ArrayList<CalorimeterHit>();
-        // loop over cells in first cluster...
-        for(int i=0; i<cells1.size(); ++i)
-        {
-            CalorimeterHit p2 = (CalorimeterHit) cells1.get(i);
-            _decoder.setID(p2.getCellID());
-            double phi = _decoder.getPhi();
-            double theta = _decoder.getTheta();
-            //distance to cluster 1
-            double dphi1=phi-phi1;
-            if(dphi1<-PI) dphi1+=TWOPI;
-            if(dphi1>PI) dphi1-=TWOPI;
-            double dtheta1 = theta-theta1;
-            double R1=dphi1*dphi1+(dtheta1)*(dtheta1);
-            // distance to cluster 2
-            double dphi2=phi-phi2;
-            if(dphi2<-PI) dphi2+=TWOPI;
-            if(dphi2>PI) dphi2-=TWOPI;
-            double dtheta2 = theta-theta2;
-            double R2=dphi2*dphi2+(dtheta2)*(dtheta2);
-     
-            if (R2<R1)
-            {
-                //add this cell to the vector of cells to remove
-                tmp.add(p2);
-            }
-        }
-        for(int i=0; i<tmp.size(); ++i)
-        {
-            CalorimeterHit p2 = (CalorimeterHit) tmp.get(i);
-            // remove this cell from cluster1
-            cells1.remove(p2);
-            // add it to cluster2
-            cells2.add(p2);
-        }
-        tmp.clear();
-        // repeat for cluster 2
-        // only loop over cells in original cluster
-        for(int i=0; i<size2; ++i)
-        {
-            CalorimeterHit p2 = (CalorimeterHit) cells2.get(i);
-            _decoder.setID(p2.getCellID());
-            double phi = _decoder.getPhi();
-            double theta = _decoder.getTheta();
-            //distance to cluster 1
-            double dphi1=phi-phi1;
-            if(dphi1<-PI) dphi1+=TWOPI;
-            if(dphi1>PI) dphi1-=TWOPI;
-            double dtheta1 = theta-theta1;
-            double R1=dphi1*dphi1+(dtheta1)*(dtheta1);
-            // distance to cluster 2
-            double dphi2=phi-phi2;
-            if(dphi2<-PI) dphi2+=TWOPI;
-            if(dphi2>PI) dphi2-=TWOPI;
-            double dtheta2 = theta-theta2;
-            double R2=dphi2*dphi2+(dtheta2)*(dtheta2);
-     
-            if (R1<R2)
-            {
-                //add this cell to the vector of cells to remove
-                tmp.add(p2);
-            }
-        }
-        for(int i=0; i<tmp.size(); ++i)
-        {
-            CalorimeterHit p2 = (CalorimeterHit) tmp.get(i);
-            // remove this cell from cluster2
-            cells2.remove(p2);
-            // add it to cluster1
-            cells1.add(p2);
-        }
-        c1.calculateVec();
-        c2.calculateVec();
-    }
-     
     
     public String toString()
     {

lcsim/src/org/lcsim/recon/cluster/nn
CreateNNClusters.java added at 1.1
diff -N CreateNNClusters.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ CreateNNClusters.java	8 Jul 2005 17:15:07 -0000	1.1
@@ -0,0 +1,90 @@
+package org.lcsim.recon.cluster.nn;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.geometry.CalorimeterIDDecoder;
+import org.lcsim.recon.cluster.util.*;
+import org.lcsim.util.Driver;
+
+/**
+ * Class to create a list of of Nearest Neighbor clusters
+ * @author Norman A. Graf with additions of threshold code by Eric J. Benavidez ([log in to unmask])
+ */
+public class CreateNNClusters 
+{
+   // the minimum number of cells to qualify as a cluster
+   private int _minNcells;
+   
+   // the neighborhood in u to search
+   private int _dU;
+   // the neighborhood in v to search
+   private int _dV;
+   // the neighborood in layers to search
+   private int _dLayer;
+   // energy threshold
+   private double _thresh;
+   
+	/**
+	 */
+	public CreateNNClusters()
+	{
+		this(1, 1, 1, 1, 0.);
+	}
+	/**
+	 */
+	public CreateNNClusters(int dU, int dV, int dLayer, int ncells, double threshold)
+	{
+		_dU = dU;
+		_dV = dV;
+		_dLayer = dLayer;
+		_minNcells = ncells;
+		_thresh = threshold;
+	}
+	public void setGrid(int dU, int dV, int dLayer)
+	{
+		_dU = dU;
+		_dV = dV;
+		_dLayer = dLayer;
+	}
+	public void setMinNcells(int ncells)
+	{
+		_minNcells = ncells;
+	}
+	public void setThreshold(double threshold)
+	{
+		_thresh = threshold;
+	}
+	public List<BasicCluster> findClusters(List<CalorimeterHit> hitlist, CalorimeterIDDecoder decoder)
+	{
+        // create a map of cells keyed on their index
+		List<BasicCluster> clusters = new ArrayList();
+        Map<Long, CalorimeterHit> hitmap = new HashMap<Long, CalorimeterHit>();
+        for (CalorimeterHit hit : hitlist)
+        {
+           long id = hit.getCellID();
+           hitmap.put(id, hit);
+        }
+        while (!hitmap.isEmpty())
+        {
+           Long k = hitmap.keySet().iterator().next();
+           CalorimeterHit hit = hitmap.get(k);
+            // start a cluster, constructor will aggregate remaining hits unto itself
+            // NB : Must pass the threshold into the constructor, otherwise threshold
+            // will not be used.
+           NearestNeighborCluster nnclus = new NearestNeighborCluster(decoder, hitmap, hit, k, _dU, _dV, _dLayer, _thresh);
+           if(nnclus.getCalorimeterHits().size()>_minNcells)
+           {
+              clusters.add(nnclus);
+           }
+        }
+		return clusters;
+    }
+   
+}

lcsim/src/org/lcsim/recon/cluster/nn
NearestNeighborCluster.java 1.4 -> 1.5
diff -u -r1.4 -r1.5
--- NearestNeighborCluster.java	23 Jun 2005 23:25:57 -0000	1.4
+++ NearestNeighborCluster.java	8 Jul 2005 17:15:07 -0000	1.5
@@ -11,7 +11,7 @@
  * @author Norman A. Graf with additions of threshold code by Eric J. Benavidez ([log in to unmask])
  * @version 1.0
  */
-public class NearestNeighborCluster extends HitsCluster
+public class NearestNeighborCluster extends BasicCluster
 {
    /**
     * Construct a NearestNeighborCluster. Note that the constructor actually performs the
@@ -81,4 +81,4 @@
    {
       return "NearestNeighborCluster with "+hits.size()+ " calorimeter hits";
    }
-}
\ No newline at end of file
+}

lcsim/src/org/lcsim/recon/cluster/nn
NearestNeighborClusterer.java 1.5 -> 1.6
diff -u -r1.5 -r1.6
--- NearestNeighborClusterer.java	23 Jun 2005 23:26:17 -0000	1.5
+++ NearestNeighborClusterer.java	8 Jul 2005 17:15:07 -0000	1.6
@@ -10,7 +10,7 @@
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.SimCalorimeterHit;
 import org.lcsim.geometry.CalorimeterIDDecoder;
-import org.lcsim.recon.cluster.nn.NearestNeighborCluster;
+import org.lcsim.recon.cluster.util.*;
 import org.lcsim.util.Driver;
 
 /**
@@ -32,6 +32,8 @@
    private int _dLayer;
    // energy threshold
    private double _thresh;
+   // Create clusters class
+   private CreateNNClusters cnnc;
    
    /**
     * Creates a new instance of NearestNeighborClusterer with a domain of (1,1,1)
@@ -60,6 +62,7 @@
       _dLayer = dLayer;
       _minNcells = ncells;
       _thresh = threshold;
+      cnnc = new CreateNNClusters(_dU,_dV,_dLayer,_minNcells,_thresh);
    }
    
    /**
@@ -90,28 +93,8 @@
       for (List<CalorimeterHit> collection: collections)
       {
          CalorimeterIDDecoder decoder = (CalorimeterIDDecoder) event.getMetaData(collection).getIDDecoder();
-         List clusters = new ArrayList();
+         List<BasicCluster> clusters = cnnc.findClusters(collection,decoder);
          
-         // create a map of cells keyed on their index
-         Map<Long, CalorimeterHit> hitmap = new HashMap<Long, CalorimeterHit>();
-         for (CalorimeterHit hit : collection)
-         {
-            long id = hit.getCellID();
-            hitmap.put(id, hit);
-         }
-         while (!hitmap.isEmpty())
-         {
-            Long k = hitmap.keySet().iterator().next();
-            CalorimeterHit hit = hitmap.get(k);
-            // start a cluster, constructor will aggregate remaining hits unto itself
-            // NB : Must pass the threshold into the constructor, otherwise threshold
-            // will not be used.
-            NearestNeighborCluster nnclus = new NearestNeighborCluster(decoder, hitmap, hit, k, _dU, _dV, _dLayer, _thresh);
-            if(nnclus.getCalorimeterHits().size()>_minNcells)
-            {
-               clusters.add(nnclus);
-            }
-         }
          String name = event.getMetaData(collection).getName();
          if (clusters.size() > 0)
              event.put(name+"NNClusters",clusters);

lcsim/src/org/lcsim/recon/cluster/util
ClusterESort.java added at 1.1
diff -N ClusterESort.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ClusterESort.java	8 Jul 2005 17:15:08 -0000	1.1
@@ -0,0 +1,31 @@
+package org.lcsim.recon.cluster.util;
+
+import java.util.Comparator;
+import org.lcsim.event.Cluster;
+/** A Comparator for sorting Clusters
+ * @author Norman A. Graf
+ * @version 1.0
+ */
+public class ClusterESort implements Comparator
+{
+    
+    /** The compare function used for sorting.
+     * Comparison is done on cluster energy.
+     * @param   obj1 Cluster1
+     * @param   obj2 Cluster2
+     * @return
+     * <ol>
+     * <li> -1 if Cluster1 > Cluster2
+     * <li>  0 if Cluster1 = Cluster2
+     * <li>  1 if Cluster1 < Cluster2
+     * </ol>
+     */
+    public int compare(Object obj1, Object obj2)
+    {
+        if(obj1==obj2) return 0;
+        Cluster v1 = (Cluster) obj1;
+        Cluster v2 = (Cluster) obj2;
+        if(v1.getEnergy()-v2.getEnergy()>0.) return -1;
+        return 1;
+    }
+}

lcsim/src/org/lcsim/recon/cluster/util
FCClusterPropertyCalculator.java added at 1.1
diff -N FCClusterPropertyCalculator.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ FCClusterPropertyCalculator.java	8 Jul 2005 17:15:08 -0000	1.1
@@ -0,0 +1,330 @@
+package org.lcsim.recon.cluster.util;
+
+import java.util.List;
+import org.lcsim.spacegeom.PrincipalAxesLineFitter;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.CalorimeterIDDecoder;
+import org.lcsim.util.fourvec.Lorentz4Vector;
+import org.lcsim.util.fourvec.Momentum4Vector;
+
+/**
+ * A class encapsulating the behavior of a calorimeter cluster.
+ *
+ * @author Norman A. Graf
+ * @version 1.0
+ */
+public class FCClusterPropertyCalculator implements ClusterPropertyCalculator
+{
+    private CalorimeterIDDecoder _decoder;
+    private Lorentz4Vector _vec;
+    // second moment of the cluster
+    private double _width;
+    private double[] _layerEnergy;
+    private double _clusterEnergy;
+    private double[] _layerWidth;
+    private double[] _centroid;
+    private double[] _directionCosines;
+    private double _samplingFraction;
+    private CalorimeterHit _hottestCell;
+    private double _highestCellEnergy;
+    private boolean _isEndCap;
+    private boolean _isNorth;
+    private double _chisq = 99999.;   
+	private int layers;
+	private double _itheta;
+	private double _iphi;
+    
+    /**
+     * Fully qualified constructor
+     *
+     * @param   decoder  The CalorimeterIDDecoder used for indexing
+     * @param   vec   The Lorentz four-vector
+     * @param   members  A Vector of CalorimeterHits
+     * @param   layers  The number of layers in the Calorimeter
+     * @param   samplingFraction The conversion from measured to deposited energy
+     */
+	public FCClusterPropertyCalculator(CalorimeterIDDecoder decoder)
+	{
+		_decoder = decoder;
+		layers = 64;
+	}
+	public void calculateProperties(List<CalorimeterHit> hits)
+	{
+        _vec = calculateVec(hits);
+        _layerEnergy = new double[layers];
+        _layerWidth = new double[layers];
+        // the array of cell (x,y,z) coordinates
+        double[][] points = new double[3][hits.size()];
+        int npoints=0;
+		_highestCellEnergy = 0.;
+        
+        for(CalorimeterHit h : hits )
+        {
+		//	Subdetector d = hit.getSubdetector();
+		//	double _sampling_fraction = d.getSamplingFraction();
+			double _sampling_fraction = 1.;
+			_decoder.setID(h.getCellID());
+            // this is a change...
+            // incorporate sampling fractions to get correct cluster energy
+            double e = h.getEnergy()/_samplingFraction;
+            if (e>_highestCellEnergy)
+            {
+                _highestCellEnergy = e;
+                _hottestCell = h;
+                // for now let highest energy cells determine location
+//                _isEndCap = cell.isEndcap();
+//                _isNorth = cell.isNorth();
+            }
+            // calculate the energy-weighted cluster width (second moment)
+            double dtheta=_vec.theta() - _decoder.getTheta();
+            double dphi=_vec.phi() - _decoder.getPhi();
+            // phi-wrap at 0:2pi?
+            if (dphi>Math.PI)
+            {
+                dphi-=2.*Math.PI;
+            }
+            if (dphi<-Math.PI)
+            {
+                dphi+=2.*Math.PI;
+            }
+            double dRw=(dtheta*dtheta + dphi*dphi)*e;
+            _width+=dRw;
+            // increment the energy deposited in this layer
+            _layerEnergy[_decoder.getLayer()]+=e;
+            _clusterEnergy+=e;
+            // increment the width (second moment of energy) in this layer
+            _layerWidth[_decoder.getLayer()]+=dRw;
+            //store the hit (x,y,z) coordinates
+            points[0][npoints] = _decoder.getX();
+            points[1][npoints] = _decoder.getY();
+            points[2][npoints] = _decoder.getZ();
+            npoints++;
+        }
+        // normalize the second moments
+        _width /= _clusterEnergy;
+        for(int i=0; i<layers; ++i)
+        {
+            _layerWidth[i]/=_clusterEnergy;
+        }
+        
+        // fit a straight line through the cells and store the results
+        PrincipalAxesLineFitter lf = new PrincipalAxesLineFitter();
+        lf.fit(points);
+        _centroid = lf.centroid();
+        _directionCosines = lf.dircos();
+		double dr = Math.sqrt( (_centroid[0]+_directionCosines[0])*(_centroid[0]+_directionCosines[0]) +
+					(_centroid[1]+_directionCosines[1])*(_centroid[1]+_directionCosines[1]) +
+					(_centroid[2]+_directionCosines[2])*(_centroid[2]+_directionCosines[2]) ) -
+					Math.sqrt(	(_centroid[0])*(_centroid[0]) +
+					(_centroid[1])*(_centroid[1]) +
+					(_centroid[2])*(_centroid[2]) ) ;
+		double sign = 1.;
+		if(dr < 0.)sign = -1.;
+		_itheta = Math.acos(_directionCosines[2]);
+		_iphi = Math.atan2(_directionCosines[1],_directionCosines[0]);
+
+        // finish up the cluster (base class method)
+//        calculateDerivedQuantities();
+    }
+    
+    /**
+     * Calculate the cluster four-momentum.
+     * The Lorentz four-vector is derived from the cluster cells.
+     *
+     */
+    public Lorentz4Vector calculateVec(List<CalorimeterHit> hits)
+    {
+        Lorentz4Vector sum = new Momentum4Vector();
+		double[] sums = {0.,0.,0.};
+		double wtsum = 0.;
+		for(int i=0;i<hits.size();i++)
+		{
+			CalorimeterHit hit = hits.get(i);
+		//	Subdetector d = hit.getSubdetector();
+		//	double sampling_fraction = d.getSamplingFraction();
+			double sampling_fraction = 1.;
+			double[] pos = new double[3];
+			_decoder.setID(hit.getCellID());
+			pos[0] = _decoder.getX();
+			pos[1] = _decoder.getY();
+			pos[2] = _decoder.getZ();
+			double wt = hit.getEnergy()/sampling_fraction;
+			wtsum += wt;
+			for(int j=0;j<3;j++)
+			{
+				sums[j] += wt*pos[j];
+			}
+		}
+		sum.plusEquals(new Momentum4Vector(sums[0], sums[1], sums[2], wtsum));
+        return sum;
+    }
+    
+    /**
+     * The cluster width (energy second moment).
+     *
+     * @return The cluster width
+     */
+    public double width()
+    {
+        return _width;
+    }
+    
+    /**
+     * The cluster four-momentum
+     *
+     * @return The Lorentz four-vector
+     */
+    public Lorentz4Vector vector()
+    {
+        return _vec;
+    }
+    
+    /**
+     * The constituent cells
+     *
+     * @return Vector of the CalorimeterHits constituting the cluster.
+     */
+    /**
+     * The cluster energy deposited in a specific layer
+     *
+     * @return  The cluster energy in layer <b>layer</b>
+     */
+    public double layerEnergy(int layer)
+    {
+        return _layerEnergy[layer];
+    }
+    
+    /**
+     * The cluster layer energies
+     *
+     * @return  The array of cluster energies in each layer.
+     */
+    public double[] layerEnergies()
+    {
+        return _layerEnergy;
+    }
+    
+    
+    /**
+     * The cluster energy corrected for sampling fractions
+     *
+     * @return  The cluster energy
+     */
+    public double clusterEnergy()
+    {
+        return _clusterEnergy;
+    }
+    
+    /**
+     * The energy of the highest energy cell in this cluster
+     *
+     * @return The energy of the highest energy cell in this cluster corrected by the sampling fraction.
+     */
+    public double highestCellEnergy()
+    {
+        return _highestCellEnergy;
+    }
+    
+    /**
+     * The CalorimeterHit in this cluster with the highest energy
+     *
+     * @return  The CalorimeterHit in this cluster with the highest energy
+     */
+    public CalorimeterHit hottestCell()
+    {
+        return _hottestCell;
+    }
+    
+    /**
+     * The cluster width (energy second moment) deposited in a specific layer
+     *
+     * @return  The cluster width in layer <b>layer</b>
+     */
+    public double layerWidth(int layer)
+    {
+        return _layerWidth[layer];
+    }
+    
+    /**
+     * The unweighted spatial centroid (x,y,z) of the cluster line fit
+     *
+     * @return The unweighted spatial centroid (x,y,z) of the cluster
+     */
+    public double[] centroid()
+    {
+        return _centroid;
+    }
+    
+    /**
+     * The direction cosines of the cluster line fit
+     *
+     * @return The direction cosines of the cluster
+     */
+    public double[] directionCosines()
+    {
+        return _directionCosines;
+    }
+    
+    
+    /**
+     * Returns topological position of cluster.
+     *
+     * @return true if in EndCap
+     */
+    public boolean isEndCap()
+    {
+        return _isEndCap;
+    }
+    
+    
+    /**
+     * Returns topological position of cluster.
+     *
+     * @return  true if in "North" EndCap
+     */
+    public boolean isNorth()
+    {
+        return _isNorth;
+    }
+    
+    public void setChisq(double chisq)
+    {
+        _chisq = chisq;
+    }
+    
+    public double chisq()
+    {
+        return _chisq;
+    }
+	public double[] getPosition()
+	{
+		return _centroid;
+	}
+	public double[] getPositionError()
+	{
+		double[] positionError = {0.,0.,0.,0.,0.,0.};
+		return positionError;
+	}
+	public double getIPhi()
+	{
+		return _iphi;
+	}
+	public double getITheta()
+	{
+		return _itheta;
+	}
+	public double[] getDirectionError()
+	{
+		double[] directionError = {0.,0.,0.,0.,0.,0.};
+		return directionError;
+	}
+	public double[] getShapeParameters()
+	{
+		double[] shapeParameters = {0.,0.,0.,0.,0.,0.};
+		shapeParameters[0] = _width;
+		return shapeParameters;
+	}
+    
+    
+}
+

lcsim/src/org/lcsim/recon/cluster/util
CalorimeterCluster.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- CalorimeterCluster.java	28 Jun 2005 06:03:56 -0000	1.3
+++ CalorimeterCluster.java	8 Jul 2005 17:15:07 -0000	1.4
@@ -13,7 +13,7 @@
  * @author Norman A. Graf
  * @version 1.0
  */
-public class CalorimeterCluster extends HitsCluster
+public class CalorimeterCluster extends BasicCluster
 {
     private CalorimeterIDDecoder _decoder;
     private Lorentz4Vector _vec;

lcsim/src/org/lcsim/recon/cluster/util
BasicCluster.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- BasicCluster.java	30 Jun 2005 20:52:09 -0000	1.1
+++ BasicCluster.java	8 Jul 2005 17:15:08 -0000	1.2
@@ -36,21 +36,21 @@
 	 * Add a CalorimeterHit to the cluster
 	 */
 	public void addHit(CalorimeterHit hit)
-    {
-	   hits.add(hit);
-       raw_energy += hit.getEnergy();
+	{
+		hits.add(hit);
+		raw_energy += hit.getEnergy();
 		/*
-	   Subdetector d = hit.getSubdetector();
-	   int detector_index = detectors.indexOf(d);
-	   if(detector_index <0)
-	   {
-		   detectors.add(d);
-		   detector_index = detectors.indexOf(d);
-		   subdetector_raw_energies.add(0.);
-		   subdetector_corrected_energies.add(0.);
-	   }
-	   double sampling_fraction = d.getSamplingFraction();
-	   */
+		 Subdetector d = hit.getSubdetector();
+		 int detector_index = detectors.indexOf(d);
+		 if(detector_index <0)
+		 {
+		 detectors.add(d);
+		 detector_index = detectors.indexOf(d);
+		 subdetector_raw_energies.add(0.);
+		 subdetector_corrected_energies.add(0.);
+		 }
+		 double sampling_fraction = d.getSamplingFraction();
+		 */
 		int detector_index = 0;
 		double sampling_fraction = 1.;
 		if(subdetector_raw_energies.size() < 1)
@@ -58,13 +58,43 @@
 			subdetector_raw_energies.add(0.);
 			subdetector_corrected_energies.add(0.);
 		}
-	   double hce = hit.getEnergy()/sampling_fraction;
-       corrected_energy += hce;
-	   hit_energies.add(hce);
-	   subdetector_raw_energies.set(detector_index,subdetector_raw_energies.get(detector_index) + hit.getEnergy());
-	   subdetector_corrected_energies.set(detector_index,subdetector_corrected_energies.get(detector_index) + hce);
-       needsPropertyCalculation = true;
-    }
+		double hce = hit.getEnergy()/sampling_fraction;
+		corrected_energy += hce;
+		hit_energies.add(hce);
+		subdetector_raw_energies.set(detector_index,subdetector_raw_energies.get(detector_index) + hit.getEnergy());
+		subdetector_corrected_energies.set(detector_index,subdetector_corrected_energies.get(detector_index) + hce);
+		needsPropertyCalculation = true;
+	}
+
+	/** 
+	 * Remove a CalorimeterHit from the cluster
+	 */
+	public void removeHit(CalorimeterHit hit)
+	{
+		int indx = hits.indexOf(hit);
+		hits.remove(hit);
+		raw_energy -= hit.getEnergy();
+		/*
+		 Subdetector d = hit.getSubdetector();
+		 int detector_index = detectors.indexOf(d);
+		 if(detector_index <0)
+		 {
+		 detectors.add(d);
+		 detector_index = detectors.indexOf(d);
+		 subdetector_raw_energies.add(0.);
+		 subdetector_corrected_energies.add(0.);
+		 }
+		 double sampling_fraction = d.getSamplingFraction();
+		 */
+		int detector_index = 0;
+		double sampling_fraction = 1.;
+		double hce = hit.getEnergy()/sampling_fraction;
+		corrected_energy -= hce;
+		hit_energies.remove(indx);
+		subdetector_raw_energies.set(detector_index,subdetector_raw_energies.get(detector_index) - hit.getEnergy());
+		subdetector_corrected_energies.set(detector_index,subdetector_corrected_energies.get(detector_index) - hce);
+		needsPropertyCalculation = true;
+	}
 	/** 
 	 * Add a Cluster to the cluster
 	 */
@@ -137,7 +167,6 @@
 	   if(needsPropertyCalculation)
 	   {
 		   calculateProperties();
-		   needsPropertyCalculation = false;
 	   }
        return iphi;
     }
@@ -150,7 +179,6 @@
 	   if(needsPropertyCalculation)
 	   {
 		   calculateProperties();
-		   needsPropertyCalculation = false;
 	   }
 	   return itheta;
     }
@@ -163,7 +191,6 @@
 		if(needsPropertyCalculation)
 		{
 			calculateProperties();
-			needsPropertyCalculation = false;
 		}
 		return directionError;
 	}
@@ -176,7 +203,6 @@
 		if(needsPropertyCalculation)
 		{
 			calculateProperties();
-			needsPropertyCalculation = false;
 		}
 		return position;
 	}
@@ -189,7 +215,6 @@
 	   if(needsPropertyCalculation)
 	   {
 		   calculateProperties();
-		   needsPropertyCalculation = false;
 	   }
 	   return positionError;
     }
@@ -202,7 +227,6 @@
 	   if(needsPropertyCalculation)
 	   {
 		   calculateProperties();
-		   needsPropertyCalculation = false;
 	   }
 	   return shapeParameters;
     }
@@ -266,6 +290,7 @@
 		itheta = cluster_property_calculator.getITheta();
 		directionError = cluster_property_calculator.getDirectionError();
 		shapeParameters = cluster_property_calculator.getShapeParameters();
+		needsPropertyCalculation = false;
 	}
 		
 }

lcsim/src/org/lcsim/recon/cluster/util
DefaultClusterPropertyCalculator.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- DefaultClusterPropertyCalculator.java	30 Jun 2005 20:53:49 -0000	1.1
+++ DefaultClusterPropertyCalculator.java	8 Jul 2005 17:15:08 -0000	1.2
@@ -39,8 +39,17 @@
 		for(int i=0;i<hits.size();i++)
 		{
 			CalorimeterHit hit = hits.get(i);
+		//	CalorimeterIDDecoder decoder = hit.getDecoder();
+		//	decoder.setID(hit.getCellID());
+		//	double[] pos = new double[3];
+		//	pos[0] = decoder.getX();
+		//	pos[1] = decoder.getY();
+		//	pos[2] = decoder.getZ();
 			double[] pos = hit.getPosition();
-			double wt = hit.getEnergy();
+		//	Subdetector d = hit.getSubdetector();
+		//	double sampling_fraction = d.getSamplingFraction();
+			double sampling_fraction = 1.;
+			double wt = hit.getEnergy()/sampling_fraction;
 			wtsum += wt;
 			for(int j=0;j<3;j++)
 			{

lcsim/src/org/lcsim/recon/cluster/util
TensorClusterPropertyCalculator.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- TensorClusterPropertyCalculator.java	30 Jun 2005 20:55:23 -0000	1.1
+++ TensorClusterPropertyCalculator.java	8 Jul 2005 17:15:08 -0000	1.2
@@ -5,6 +5,7 @@
 import java.util.List;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
+import org.lcsim.geometry.CalorimeterIDDecoder;
 
 /**
  * Implementation of ClusterPropertyCalculator Interface using
@@ -71,6 +72,12 @@
 		for(int i=0;i<hits.size();i++)
 		{
 			CalorimeterHit hit = hits.get(i);
+		//	CalorimeterIDDecoder decoder = hit.getDecoder();
+		//	decoder.setID(hit.getCellID());
+		//	double[] pos = new double[3];
+		//	pos[0] = decoder.getX();
+		//	pos[1] = decoder.getY();
+		//	pos[2] = decoder.getZ();
 			double[] pos = hit.getPosition();
 		//	Subdetector d = hit.getSubdetector();
 		//	double sampling_fraction = d.getSamplingFraction();
CVSspam 0.2.8