Print

Print


Commit in hps-java/src/main/java/org/lcsim/hps on MAIN
analysis/ecal/HPSEcalPlotsDriver.java+518added 1.1
recon/ecal/HPSEcalClusterer.java+194added 1.1
+712
2 added files
move ecal code from lcsim-contrib

hps-java/src/main/java/org/lcsim/hps/analysis/ecal
HPSEcalPlotsDriver.java added at 1.1
diff -N HPSEcalPlotsDriver.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSEcalPlotsDriver.java	16 May 2011 19:14:29 -0000	1.1
@@ -0,0 +1,518 @@
+package org.lcsim.contrib.jeremym.hps;
+
+import hep.aida.ICloud1D;
+import hep.aida.ICloud2D;
+import hep.aida.IHistogram1D;
+import hep.physics.vec.Hep3Vector;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.units.SystemOfUnits;
+import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
+
+/**
+ * Diagnostic plots for HPS ECal.
+ * 
+ * @author Jeremy McCormick <[log in to unmask]>
+ * @version $Id: HPSEcalPlotsDriver.java,v 1.1 2011/05/16 19:14:29 jeremy Exp $
+ */
+// TODO ZY plot can use h2d with small bins in Y to avoid weird binning effect
+// TODO ZY of cluster positions (algo from Tim to find pos)
+// TODO ZY of cluster seed
+
+public class HPSEcalPlotsDriver extends Driver 
+{
+    String ecalCollectionName = "EcalHits";
+    String ecalClusterCollectionName = "EcalClusters";
+    
+    AIDA aida = AIDA.defaultInstance();
+
+    // MCParticle plots.
+    ICloud1D primaryEPlot;
+    ICloud1D fsPlot;
+    
+    // CalHit plots.
+    IHistogram1D hitEPlot;
+    ICloud1D ecalEPlot; 
+    ICloud1D eventEPlot;       
+    ICloud2D hitXZPlot;
+    ICloud2D hitYZPlot;
+    ICloud1D hitUnder100MeVPlot;
+    IHistogram1D hitOver100MeVPlot;
+    ICloud1D maxHitEPlot;    
+    IHistogram1D maxTimePlot;
+    ICloud1D timePlot;
+    ICloud1D hitCountPlot;
+    ICloud1D idCountPlot;
+    
+    // Cluster plots.
+    IHistogram1D nclusPlot;
+    ICloud1D clusEPlot;
+    ICloud1D clusTotEPlot;           
+    ICloud1D leadClusEPlot;
+    ICloud1D leadClus2EPlot;
+    ICloud1D clusResTop3Plot;
+    IHistogram1D clusHitPlot;
+    ICloud1D clusSeedEPlot;
+    ICloud1D clusSeedDistPlot;
+    ICloud2D leadClusAndPrimaryPlot;
+
+    //ICloud1D hit50MeVPlot;
+    //ICloud1D hit30MeVPlot;
+    
+    //ICloud1D residualAllPlot;
+    //ICloud1D residualPlot;    
+    //ICloud1D residualMaxHitPlot;
+    //ICloud1D residualTop2Plot;
+    //ICloud1D residualTop3Plot;
+        
+    class MCParticleEComparator implements Comparator<MCParticle>
+    {
+        public int compare(MCParticle p1, MCParticle p2) 
+        {
+            double e1 = p1.getEnergy();
+            double e2 = p2.getEnergy();
+            if (e1 < e2)
+            {
+                return -1;
+            }
+            else if (e1 == e2)
+            {
+                return 0;
+            }
+            else
+            {
+                return 1;
+            }
+        }        
+    }
+    
+    class ClusterEComparator implements Comparator<Cluster>
+    {
+        public int compare(Cluster o1, Cluster o2) 
+        {
+            if (o1.getEnergy() < o2.getEnergy())
+            {
+                return -1;
+            }
+            else if (o1.getEnergy() > o2.getEnergy())
+            {
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+        }       
+    }
+    
+    public void startOfData()
+    {
+        timePlot = aida.cloud1D(ecalCollectionName + " : Hit Time");
+        timePlot.annotation().addItem("yAxisScale", "log");
+        timePlot.annotation().addItem("xAxisLabel", "Time [ns]");
+        
+        maxTimePlot = aida.histogram1D(ecalCollectionName + " : Max Time", 200, 0, 1000);
+        maxTimePlot.annotation().addItem("yAxisScale", "log");
+        maxTimePlot.annotation().addItem("xAxisLabel", "Time [ns]");
+        
+        maxHitEPlot = aida.cloud1D(ecalCollectionName + " : Max Hit E in Event");
+        maxHitEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        hitEPlot = aida.histogram1D(ecalCollectionName + " : Hit Energy", 200, 0, 3500);
+        hitEPlot.annotation().addItem("yAxisScale", "log");
+        hitEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        hitCountPlot = aida.cloud1D(ecalCollectionName + " : Hit Count");
+        hitCountPlot.annotation().addItem("xAxisLabel", "Number of Hits");
+        
+        idCountPlot = aida.cloud1D(ecalCollectionName + " : Uniq Hit IDs");
+        idCountPlot.annotation().addItem("xAxisLabel", "Number of Unique IDs in Event");
+        
+        ecalEPlot = aida.cloud1D(ecalCollectionName + " : Total E in Event");
+        ecalEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        primaryEPlot = aida.cloud1D("MCParticle: Highest Primary E in Event");
+        primaryEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        eventEPlot = aida.cloud1D("MCParticle: Total Gen FS Electron E in Event");
+        eventEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        //residualPlot = aida.cloud1D(ecalCollectionName + " : Residual with Highest E Particle [GeV]");
+        //residualPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        //residualAllPlot = aida.cloud1D(ecalCollectionName + " : Resdual with All Final State Electrons [GeV]");
+        //residualAllPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        //residualMaxHitPlot = aida.cloud1D(ecalCollectionName + " : Residual of Max Hit and Highest E Electron");
+        //residualMaxHitPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        hitYZPlot = aida.cloud2D(ecalCollectionName + " : Y vs Z");        
+        hitYZPlot.annotation().addItem("xAxisLabel", "Y [mm]");
+        hitYZPlot.annotation().addItem("yAxisLabel", "Z [mm]");
+        
+        hitXZPlot = aida.cloud2D(ecalCollectionName + " : X vs Z");
+        hitXZPlot.annotation().addItem("xAxisLabel", "X [mm]");
+        hitXZPlot.annotation().addItem("yAxisLabel", "Z [mm]");
+        
+        //residualTop2Plot = aida.cloud1D(ecalCollectionName + " : Residual with Top 2 FS Particle E");
+        //residualTop2Plot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        //residualTop3Plot = aida.cloud1D(ecalCollectionName + " : Residual with Top 3 FS Particle E");
+        //residualTop3Plot.annotation().addItem("xAxisLabel", "E [GeV]");              
+        
+        fsPlot  = aida.cloud1D("MCParticle: Number of Final State Particles");
+        fsPlot.annotation().addItem("xAxisLabel", "Number of FS Particles");
+        
+        clusEPlot = aida.cloud1D(ecalClusterCollectionName + " : Cluster E");
+        clusEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        nclusPlot = aida.histogram1D(ecalClusterCollectionName + " : Number of Clusters", 20, 0, 20);
+        nclusPlot.annotation().addItem("xAxisLabel", "Number of Clusters");
+        
+        //hit50MeVPlot = aida.cloud1D(ecalCollectionName + " : Hits with E < 50 MeV");
+        //hit50MeVPlot.annotation().addItem("xAxisLabel", "Number of Hits");
+        
+        //hit30MeVPlot = aida.cloud1D(ecalCollectionName + " : Hits with E < 30 MeV");
+        //hit30MeVPlot.annotation().addItem("xAxisLabel", "Number of Hits");
+        
+        hitUnder100MeVPlot = aida.cloud1D(ecalCollectionName + " : Hits with E < 100 MeV");
+        hitUnder100MeVPlot.annotation().addItem("xAxisLabel", "Number of Hits");
+        
+        hitOver100MeVPlot = aida.histogram1D(ecalCollectionName + " : Hits with E >= 100 MeV", 20, 0, 20);
+        hitUnder100MeVPlot.annotation().addItem("xAxisLabel", "Number of Hits");
+        
+        leadClusEPlot = aida.cloud1D(ecalClusterCollectionName + " : Leading Cluster E");
+        leadClusEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        leadClus2EPlot = aida.cloud1D(ecalClusterCollectionName + " : Second Leading Cluster E");
+        leadClus2EPlot.annotation().addItem("xAxisLabel", "E [GeV]");       
+        
+        clusTotEPlot = aida.cloud1D(ecalClusterCollectionName + " : Total Clus E in Event");
+        clusTotEPlot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        clusResTop3Plot = aida.cloud1D(ecalClusterCollectionName + " : Total Clus E Residual with Top 3 Particles");
+        clusResTop3Plot.annotation().addItem("xAxisLabel", "E [GeV]");
+        
+        clusHitPlot = aida.histogram1D(ecalClusterCollectionName + " : Number of Clusters per Hit", 5, 1, 6);
+        clusHitPlot.annotation().addItem("xAxisLabel", "Number of Clusters");
+        
+        clusSeedDistPlot = aida.cloud1D(ecalClusterCollectionName + " : Cluster Seed Hit Distance from Beam Axis");
+        clusSeedDistPlot.annotation().addItem("xAxisLabel", "Number of Clusters");
+        clusSeedDistPlot.annotation().addItem("yAxisScale", "log");
+        
+        clusSeedEPlot = aida.cloud1D(ecalClusterCollectionName + " : Cluster Seed Hit Distance from Beam Axis");
+        clusSeedEPlot.annotation().addItem("xAxisLabel", "Distance [mm]");
+        
+        leadClusAndPrimaryPlot = aida.cloud2D(ecalClusterCollectionName + " : Lead Cluster E vs Highest Primary Particle E");        
+    }
+            
+    public void process(EventHeader event)
+    {
+        // sum and max vars
+        double esum = 0;
+        double emax = 0;
+        double tmax = 0;
+                
+        // Loop over hits from ECal collection.
+        List<CalorimeterHit> hits = event.get(CalorimeterHit.class, ecalCollectionName);
+        int nhits = hits.size();
+        
+        // MCParticles
+        List<MCParticle> mcparticles = event.get(MCParticle.class).get(0);
+        
+        // Final State particles.
+        List<MCParticle> fsParticles = getFinalStateParticles(mcparticles);
+        
+        //System.out.println("fsParticles="+fsParticles.size());
+        fsPlot.fill(fsParticles.size());
+                        
+        // Sort MCParticles on energy.
+        Collections.sort(fsParticles, new MCParticleEComparator());
+        
+        // Energy of top two FS particles.
+        double e2 = fsParticles.get(0).getEnergy() + fsParticles.get(1).getEnergy();
+        
+        // Energy of top three FS particles.
+        double e3 = e2 + fsParticles.get(2).getEnergy();
+        
+        // Check unique IDs.
+        Set<Long> ids = new HashSet<Long>();
+        
+        // n hits
+        hitCountPlot.fill(nhits);
+        
+        //int naccept = 0;
+                               
+        //int nhits50MeV = 0;
+        //int nhits30MeV = 0;
+        int nhits100MeV = 0;
+        int nhitsOver100MeV = 0;
+        
+        // Loop over ECal hits.
+        for (CalorimeterHit hit : hits)
+        {
+            // get raw E
+            double eraw = hit.getRawEnergy();
+            
+            if (eraw >= 0.1)
+            {
+                nhitsOver100MeV++;
+            }            
+            
+            if (eraw < 0.1)
+            {
+                nhits100MeV++;
+            }
+            
+            //if (eraw < 0.05)
+            //{
+            //    nhits50MeV++;
+            //}       
+            
+            //if (eraw < 0.03)
+            //{
+            //    nhits30MeV++;
+            //}
+            
+            // time
+            timePlot.fill(hit.getTime());
+            
+            // YZ
+            hitYZPlot.fill(hit.getPosition()[1], hit.getPosition()[2]);           
+            
+            // XZ
+            hitXZPlot.fill(hit.getPosition()[0], hit.getPosition()[2]);
+                        
+            // hit E
+            hitEPlot.fill(eraw / SystemOfUnits.MeV);
+            
+            // check E max
+            if (eraw > emax)
+                emax = eraw;
+            
+            // check T max
+            if (hit.getTime() > tmax)            
+                tmax = hit.getTime();
+            
+            if (ids.contains(hit.getCellID()))
+                throw new RuntimeException("Duplicate cell ID: " + hit.getCellID());
+            
+            ids.add(hit.getCellID());
+                                    
+            // incr E sum
+            esum += eraw;
+        }
+        
+        hitUnder100MeVPlot.fill(nhits100MeV);
+        //hit50MeVPlot.fill(nhits50MeV);        
+        //hit30MeVPlot.fill(nhits30MeV);
+        hitOver100MeVPlot.fill(nhitsOver100MeV);
+                                              
+        // total E in Cal
+        ecalEPlot.fill(esum);
+        
+        // max hit E in event
+        maxHitEPlot.fill(emax);
+        
+        // max hit time
+        maxTimePlot.fill(tmax);
+        
+        // number of unique hit ids
+        idCountPlot.fill(ids.size());
+                                                      
+        // primary particle with most E
+        MCParticle primary = getPrimary(mcparticles);
+        double primaryE = primary.getEnergy();
+        primaryEPlot.fill(primaryE);
+        
+        // residual using highest E primary
+        //double singleResidual = esum - primaryE;
+        //residualPlot.fill(singleResidual);        
+     
+        // event energy                         
+        double eventE = getPrimaryE(mcparticles);
+        eventEPlot.fill(eventE);
+        
+        // event residual
+        //double residual = esum - eventE;
+        //residualAllPlot.fill(residual);
+        
+        // hottest hit residual with highest E particle
+        //residualMaxHitPlot.fill(emax - primaryE);
+        
+        // Residual with two 
+        //double res2 = esum - e2;
+        //residualTop2Plot.fill(res2);
+        
+        //double res3 = esum - e3;
+        //residualTop3Plot.fill(res3);
+
+        List<Cluster> clusters = event.get(Cluster.class, ecalClusterCollectionName);
+        if (clusters == null)
+            throw new RuntimeException("Missing cluster collection!");
+        Collections.sort(clusters, new ClusterEComparator());
+        
+        nclusPlot.fill(clusters.size());
+        
+        // Leading cluster E.
+        if (clusters.size() > 0)
+        {
+            Cluster leadClus = clusters.get(clusters.size()-1);
+            leadClusEPlot.fill(leadClus.getEnergy());
+            
+            leadClusAndPrimaryPlot.fill(primaryE, leadClus.getEnergy());
+        }
+        
+        // Second leading cluster E.
+        if (clusters.size() > 1)
+        {
+            leadClus2EPlot.fill(clusters.get(clusters.size()-2).getEnergy());
+        }
+                
+        Map<CalorimeterHit,Integer> hitClusMap = new HashMap<CalorimeterHit,Integer>();
+                        
+        double clusE = 0;
+        Set<CalorimeterHit> naughty = new HashSet<CalorimeterHit>();
+        for (Cluster clus : clusters)
+        {
+            double e = clus.getEnergy();
+            clusEPlot.fill(e);
+            clusE += e;         
+            CalorimeterHit seedHit = null;
+            double maxe = 0;
+            for (CalorimeterHit hit : clus.getCalorimeterHits())
+            {
+                if (hitClusMap.containsKey(hit))
+                {
+                    int nshared = hitClusMap.get(hit);
+                    ++nshared;
+                    
+                    // debug
+                    if (nshared >= 4)
+                        naughty.add(hit);
+                    //
+                    
+                    hitClusMap.put(hit, nshared);
+                }
+                else
+                {
+                    hitClusMap.put(hit, 1);
+                }
+                
+                if (hit.getRawEnergy() > maxe)
+                {
+                    seedHit = hit;
+                }
+            }
+            
+            // Seed distance from X axis.
+            Hep3Vector pos = seedHit.getPositionVec(); 
+            double y = pos.y();
+            double z = pos.z();
+            clusSeedEPlot.fill(Math.sqrt(y*y+z*z));
+            
+            // Seed E.
+            clusSeedEPlot.fill(seedHit.getRawEnergy());            
+        }
+        
+        // debug of clusters with too many hits
+        for (CalorimeterHit duggan : naughty)
+        {
+            for (Cluster clus : clusters)
+            {
+                if (clus.getCalorimeterHits().contains(duggan))
+                {
+                    System.out.println("naughty clus w/ " + clus.getCalorimeterHits().size() + " hits and E = " + clus.getEnergy());
+                    for (CalorimeterHit clusHit : clus.getCalorimeterHits())
+                    {
+                        IDDecoder dec = clusHit.getIDDecoder();
+                        dec.setID(clusHit.getCellID());
+                        int ix = dec.getValue("ix");
+                        int iy = dec.getValue("iy");
+                        int side = dec.getValue("side");
+                        System.out.println("  x, y, side, E: " + ix + ", " + iy + ", " + side + ", " + clusHit.getRawEnergy());
+                    }
+                }
+            }
+        }
+        
+        // Total E in all clusters.
+        clusTotEPlot.fill(clusE);
+        
+        // Residual of cluster total E and E from top 3 primary particles. 
+        clusResTop3Plot.fill(clusE - e3);        
+        
+        for (Entry<CalorimeterHit, Integer> clusHit : hitClusMap.entrySet())
+        {            
+            clusHitPlot.fill(clusHit.getValue());
+        }
+    }    
+    
+    private double getPrimaryE(List<MCParticle> particles)
+    {
+        double electronE = 0;
+        for (MCParticle particle : particles)
+        {
+            if (particle.getGeneratorStatus() == MCParticle.FINAL_STATE 
+                    && Math.abs(particle.getPDGID()) == 11)
+            {
+                electronE += particle.getEnergy();
+            }
+        }
+        return electronE;
+    }
+    
+    private MCParticle getPrimary(List<MCParticle> particles)
+    {
+        double maxE = 0;
+        MCParticle primary = null;
+        for (MCParticle particle : particles)
+        {
+            if (particle.getGeneratorStatus() == MCParticle.FINAL_STATE 
+                    && particle.getEnergy() > maxE)
+            {
+                maxE = particle.getEnergy();
+                primary = particle;
+            }
+        }
+        return primary;        
+    }
+    
+    private static List<MCParticle> getFinalStateParticles(List<MCParticle> mcparticles)
+    {
+        List<MCParticle> fsParticles = new ArrayList<MCParticle>();
+        for (MCParticle mcparticle : mcparticles)
+        {
+            if (mcparticle.getGeneratorStatus() == MCParticle.FINAL_STATE)
+            {
+                fsParticles.add(mcparticle);
+            }
+        }
+        return fsParticles;
+    }
+    
+    public void setEcalCollectionName(String ecalCollectionName)
+    {
+        this.ecalCollectionName = ecalCollectionName;
+    }
+    
+    public void setEcalClusterCollectionName(String ecalClusterCollectionName)
+    {
+        this.ecalClusterCollectionName = ecalClusterCollectionName;
+    }    
+}

hps-java/src/main/java/org/lcsim/hps/recon/ecal
HPSEcalClusterer.java added at 1.1
diff -N HPSEcalClusterer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HPSEcalClusterer.java	16 May 2011 19:14:29 -0000	1.1
@@ -0,0 +1,194 @@
+package org.lcsim.contrib.jeremym.hps;
+
+import java.util.ArrayList;
+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.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.geometry.Detector;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.geometry.subdetector.HPSEcal;
+import org.lcsim.geometry.subdetector.HPSEcal.XYSide;
+import org.lcsim.geometry.util.IDEncoder;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.util.Driver;
+import org.lcsim.util.lcio.LCIOConstants;
+
+/**
+ * Creates clusters from CalorimeterHits in the HPSEcal detector.
+ * 
+ * Clustering algorithm is from pages 83 and 84 of the HPS Proposal. 
+ * 
+ * @author Jeremy McCormick <[log in to unmask]>
+ * @version $Id: HPSEcalClusterer.java,v 1.1 2011/05/16 19:14:29 jeremy Exp $
+ */
+public class HPSEcalClusterer extends Driver 
+{
+    HPSEcal ecal;
+    
+    String ecalCollectionName;
+    String ecalName;
+    String clusterCollectionName = "EcalClusters";
+        
+    // Minimum E for cluster seed.
+    double seedEMin = .05;
+    
+    // Minimum E to add hit to cluster.
+    double addEMin = .03;
+    
+    // Odd or even number of crystals in X.
+    boolean oddX;
+    
+    public HPSEcalClusterer()
+    {}
+    
+    public void setClusterCollectionName(String clusterCollectionName)
+    {
+        this.clusterCollectionName = clusterCollectionName;
+    }
+    
+    public void setSeedEMin(double seedEMin)
+    {
+        this.seedEMin = seedEMin;
+    }
+    
+    public void setAddEMin(double addEMin)
+    {
+        this.addEMin = addEMin;
+    }
+    
+    public void setEcalCollectionName(String ecalCollectionName)
+    {
+        this.ecalCollectionName = ecalCollectionName;
+    }
+    
+    public void setEcalName(String ecalName)
+    {
+        this.ecalName = ecalName;
+    }
+    
+    public void startOfData()
+    {
+        if (ecalCollectionName == null)
+            throw new RuntimeException("The parameter ecalCollectionName was not set!");
+        
+        if (ecalCollectionName == null)
+            throw new RuntimeException("The parameter ecalName was not set!");
+        
+        System.out.println(this.getClass().getCanonicalName());
+        System.out.println(" seedEMin="+seedEMin);
+        System.out.println(" addEMin="+addEMin);    
+        System.out.println();
+    }   
+    
+    public void detectorChanged(Detector detector)
+    {
+        ecal = (HPSEcal)detector.getSubdetector(ecalName);
+                        
+        System.out.println(ecal.getName());
+        System.out.println(" nx="+ecal.nx());
+        System.out.println(" ny="+ecal.ny());
+        System.out.println(" beamgap="+ecal.beamGap());
+        System.out.println(" dface="+ecal.distanceToFace());
+    }    
+    
+    public void process(EventHeader event)
+    {                        
+        List<CalorimeterHit> hits = event.get(CalorimeterHit.class, ecalCollectionName);
+        if (hits == null)
+            throw new RuntimeException("Event is missing ECal hits collection!");
+            
+        IDDecoder dec = ecal.getIDDecoder();
+               
+        // Hit map.
+        Map<Long,CalorimeterHit> hitMap = new HashMap<Long,CalorimeterHit>();
+        
+        // Make map of x, y, and side to hit.
+        for (CalorimeterHit hit : hits)
+        {
+            dec.setID(hit.getCellID());
+            hitMap.put(hit.getCellID(), hit);
+        }
+        
+        // Setup an encoder from the decoder.
+        IDEncoder enc = new IDEncoder(dec.getIDDescription());
+        
+        // Cluster list to be added to event.
+        List<Cluster> clusters = new ArrayList<Cluster>();
+        
+        // Loop over ECal hits.
+        for (CalorimeterHit hit : hits)
+        {
+            // Cut on min seed E.
+            if (hit.getRawEnergy() < seedEMin)
+                continue;
+            
+            // Set decoder's ID.
+            dec.setID(hit.getCellID());
+            
+            // Get ID values.
+            int ix = dec.getValue("ix");
+            int iy = dec.getValue("iy");
+            int side = dec.getValue("side");
+            
+            // Get neighboring crystals to hit.
+            Set<XYSide> neighbors = ecal.getNeighbors(ix, iy, side);
+            
+            //System.out.println("neighbors of " + ix + ", " + iy + ", " + side);
+           
+            int[] buffer = new int[dec.getFieldCount()];                        
+            dec.getValues(buffer);
+            
+            // Loop over neighbors.
+            List<CalorimeterHit> neighborHits = new ArrayList<CalorimeterHit>();
+            boolean isSeed = true;
+            for (XYSide neighbor : neighbors)
+            {                             
+                buffer[dec.getFieldIndex("ix")] = neighbor.x();
+                buffer[dec.getFieldIndex("iy")] = neighbor.y();
+                buffer[dec.getFieldIndex("side")] = neighbor.side();                
+                
+                // Create ID for this crystal.
+                // FIXME This is redundant and inefficient.
+                long neighborId = enc.setValues(buffer);
+              
+                // Find neighbor hit if it exists.
+                CalorimeterHit neighborHit = hitMap.get(neighborId);
+                
+                // Got a hit?
+                if (neighborHit != null)
+                {                                             
+                    // Neighbor is hotter so skip this hit.
+                    if (neighborHit.getRawEnergy() > hit.getRawEnergy())
+                    {
+                        isSeed = false;
+                        break;
+                    } 
+                    
+                    // Add to cluster if above min E.
+                    if (neighborHit.getRawEnergy() >= addEMin)                    
+                        neighborHits.add(neighborHit);
+                }                                
+            }
+                        
+            if (isSeed)
+            {
+                // Make cluster.
+                BasicCluster cluster = new BasicCluster();
+                cluster.addHit(hit);
+                for (CalorimeterHit clusHit : neighborHits)
+                {
+                    cluster.addHit(clusHit);
+                }            
+                clusters.add(cluster);
+            }
+        }
+        
+        int flag = 1 << LCIOConstants.CLBIT_HITS;        
+        event.put(clusterCollectionName, clusters, Cluster.class, flag);        
+    }         
+}
\ No newline at end of file
CVSspam 0.2.8