Commit in lcsim/src/org/lcsim/recon/tracking/digitization/sisim on MAIN
ClusteringAlgorithm.java+35added 1.1
NearestNeighbor.java+219added 1.1
Clusterer.java-61.1 -> 1.2
GenericReadoutChip.java+28-241.2 -> 1.3
Kpix.java+27-101.1 -> 1.2
PixelHitMaker.java+41-1571.2 -> 1.3
ReadoutChip.java+1-21.1 -> 1.2
StripHitMaker.java+23-1171.1 -> 1.2
+374-316
2 added + 6 modified, total 8 files
Pull clustering algorithm out of cluster maker and use it for both strips and pixels.

Also, make the clustering thresholds settable (and independent of the readout thresholds).

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
ClusteringAlgorithm.java added at 1.1
diff -N ClusteringAlgorithm.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ClusteringAlgorithm.java	7 May 2009 22:36:21 -0000	1.1
@@ -0,0 +1,35 @@
+/*
+ * ClusteringAlgorithm.java
+ *
+ */
+
+package org.lcsim.recon.tracking.digitization.sisim;
+
+import java.util.List;
+
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.event.RawTrackerHit;
+
+/**
+ * Interface for a clustering algorithm that clusters hits on an electrodes.
+ *
+ * @author Richard Partridge
+ */
+public interface ClusteringAlgorithm {
+
+    /**
+     * Finds the clusters given a list of RawTrackerHits on a particular
+     * silicon sensor with electrodes given by SiSensorElectrodes.  A list
+     * of clusters is returned, with each cluster being a list of RawTrackerHits
+     * the form the cluster.
+     *
+     * @param sensor sensor to cluster
+     * @param electodes electrodes on this sensor to cluster
+     * @param readout readout chip for these electrodes
+     * @param hits raw hits
+     * @return list of clusters, with each cluster being a list of RawTrackerHits
+     */
+    public List<List<RawTrackerHit>> findClusters(SiSensorElectrodes electrodes,
+            ReadoutChip readout, List<RawTrackerHit> hits);
+
+}
\ No newline at end of file

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
NearestNeighbor.java added at 1.1
diff -N NearestNeighbor.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ NearestNeighbor.java	7 May 2009 22:36:21 -0000	1.1
@@ -0,0 +1,219 @@
+/*
+ * NearestNeighborClusteringAlgorithm.java
+ */
+package org.lcsim.recon.tracking.digitization.sisim;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.lcsim.detector.identifier.IIdentifier;
+import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
+import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
+import org.lcsim.event.RawTrackerHit;
+
+/**
+ * This class uses a nearest neighbor algorithm to find clusters of hits on a
+ * set of silicon sensor electrodes (i.e., an instance of SiStrips or SiPixels).
+ *
+ * The algorithm first finds possible cluster seeds that are above the seed
+ * threshold.  Starting from a seed, the neighbor strips/pixels are searched
+ * to see if we have hits above the neighbor threshold.  Neighbor channels
+ * are added until we have a cluster where every neighboring channel for the
+ * cluster has charge lying below the neighbor threshold.
+ *
+ * Thresholds are specified in units of electrons.
+ *
+ * HashMaps are used to speed up the algorithm when there are large numbers
+ * of hits, and the algorithm is expected to scale linearly with the number
+ * of RawTrackerHits on the electrodes.
+ *
+ * @author Richard Partridge
+ */
+public class NearestNeighbor implements ClusteringAlgorithm {
+
+    private static String _NAME = "NearestNeighbor";
+    private double _seed_threshold;
+    private double _neighbor_threshold;
+
+    /**
+     * Instantiate NearestNeighborClusteringAlgorithm with specified thresholds.
+     * Seed threshold is the minimum charge to initiate a cluster.  Neighbor
+     * threshold is the minimum charge to add a neighboring cell to a cluster.
+     * All thresholds are in units of electrons.
+     *
+     * @param seed_threshold seed threhold
+     * @param neighbor_threshold neighbor threshold
+     */
+    public NearestNeighbor(double seed_threshold, double neighbor_threshold) {
+
+        _seed_threshold = seed_threshold;
+        _neighbor_threshold = neighbor_threshold;
+    }
+
+    /**
+     * Instantiate NearestNeighborClusteringAlgorithm with default thresholds:
+     *
+     * seed_threshold = 4000 electrons
+     * neighbor_threhold = 2000 electrons
+     */
+    public NearestNeighbor() {
+        this(4000., 2000.);
+    }
+
+    /**
+     * Set the seed threshold.  Units are electrons.
+     *
+     * @param seed_threshold seed threshold
+     */
+    public void setSeedThreshold(double seed_threshold) {
+        _seed_threshold = seed_threshold;
+    }
+
+    /**
+     * Set the neighbor threshold.  Units are electrons.
+     *
+     * @param neighbor_threshold neighbor threshold
+     */
+    public void setNeighborThreshold(double neighbor_threshold) {
+        _neighbor_threshold = neighbor_threshold;
+    }
+
+    /**
+     * Return the seed threshold.  Units are electrons.
+     *
+     * @return seed threshold
+     */
+    public double getSeedThreshold() {
+        return _seed_threshold;
+    }
+
+    /**
+     * Return the neighbor threshold.  Units are electrons.
+     *
+     * @return neighbor threshold
+     */
+    public double getNeighborThreshold() {
+        return _neighbor_threshold;
+    }
+
+    /**
+     * Return the name of the clustering algorithm.
+     * 
+     * @return _name clusting algorithm name
+     */
+    public String getName() {
+        return _NAME;
+    }
+
+    /**
+     * Find clusters using the nearest neighbor algorithm.
+     *
+     * @param sensor sensor containing the electrodes
+     * @param electrodes electrodes we are clustering
+     * @param readout_chip readout chip for these electrodes
+     * @param raw_hits List of RawTrackerHits to be clustered
+     * @return list of clusters, with a cluster being a list of RawTrackerHits
+     */
+    public List<List<RawTrackerHit>> findClusters(SiSensorElectrodes electrodes,
+            ReadoutChip readout_chip, List<RawTrackerHit> raw_hits) {
+
+        //  Check that the seed threshold is at least as large as  the neighbor threshold
+        if (_seed_threshold < _neighbor_threshold) {
+            throw new RuntimeException("Tracker hit clustering error: seed threshold below neighbor threshold");
+        }
+
+        //  Create maps that show the channel status and relate the channel number to the raw hit and vice versa
+        Map<Integer, Boolean> clusterable = new HashMap<Integer, Boolean>();
+        Map<RawTrackerHit, Integer> hit_to_channel = new HashMap<RawTrackerHit, Integer>();
+        Map<Integer, RawTrackerHit> channel_to_hit = new HashMap<Integer, RawTrackerHit>();
+
+        //  Create list of channel numbers to be used as cluster seeds
+        List<Integer> cluster_seeds = new ArrayList<Integer>();
+
+        //  Loop over the raw hits and construct the maps used to relate cells and hits, initialize the
+        //  clustering status map, and create a list of possible cluster seeds
+        for (RawTrackerHit raw_hit : raw_hits) {
+
+            // get the channel number for this hit
+            IIdentifier id = raw_hit.getIdentifier();
+            SiTrackerIdentifierHelper _sid_helper = (SiTrackerIdentifierHelper) raw_hit.getIdentifierHelper();
+            int channel_number = _sid_helper.getElectrodeValue(id);
+
+            //  Check for duplicate RawTrackerHits or channel numberss
+            if (hit_to_channel.containsKey(raw_hit) || channel_to_hit.containsKey(channel_number)) {
+                throw new RuntimeException("Duplicate hit or channel number");
+            }
+
+            //  Add this hit to the maps that relate channels and hits
+            hit_to_channel.put(raw_hit, channel_number);
+            channel_to_hit.put(channel_number, raw_hit);
+
+            //  Get the signal from the readout chip (units are electrons)
+            double signal = readout_chip.decodeCharge(raw_hit);
+
+            //  Mark this hit as available for clustering if it is above the neighbor threshold
+            clusterable.put(channel_number, signal >= _neighbor_threshold);
+
+            //  Add this hit to the list of seeds if it is above the seed threshold
+            if (signal >= _seed_threshold) cluster_seeds.add(channel_number);
+        }
+
+        //  Create a list of clusters
+        List<List<RawTrackerHit>> cluster_list = new ArrayList<List<RawTrackerHit>>();
+
+        //  Now loop over the cluster seeds to form clusters
+        for (int seed_channel : cluster_seeds) {
+
+            //  First check if this hit is still available for clustering
+            if (!clusterable.get(seed_channel)) continue;
+
+            //  Create a new cluster
+            List<RawTrackerHit> cluster = new ArrayList<RawTrackerHit>();
+
+            //  Create a queue to hold channels whose neighbors need to be checked for inclusion
+            LinkedList<Integer> unchecked = new LinkedList<Integer>();
+
+            //  Add the seed channel to the unchecked list and mark it as unavailable for clustering
+            unchecked.addLast(seed_channel);
+            clusterable.put(seed_channel, false);
+
+            //  Check the neighbors of channels added to the cluster
+            while (unchecked.size() > 0) {
+
+                //  Pull the next channel off the queue and add it's hit to the cluster
+                int clustered_cell = unchecked.removeFirst();
+                cluster.add(channel_to_hit.get(clustered_cell));
+
+                //  Get the neigbor channels
+                Set<Integer> neighbor_channels = electrodes.getNearestNeighborCells(clustered_cell);
+
+                //   Now loop over the neighbors and see if we can add them to the cluster
+                for (int channel : neighbor_channels) {
+
+                    //  First see if this neighbor channel is in our clusterable hit map
+                    if (clusterable.containsKey(channel)) {
+
+                        //  Now check if this neighbor channel is still available for clustering
+                        if (clusterable.get(channel)) {
+
+                            //  Add channel to the list of unchecked clustered channels
+                            //  and mark it unavailable for clustering
+                            unchecked.addLast(channel);
+                            clusterable.put(channel, false);
+                        }
+                    }
+                }  // end of loop over neighbor cells
+            }  // end of loop over unchecked cells
+
+            //  Finished with this cluster - add it to the list of clusters
+            if (cluster.size() > 0) cluster_list.add(cluster);
+
+        }  //  End of loop over seeds
+
+        //  Finished finding clusters
+        return cluster_list;
+    }
+}

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
Clusterer.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Clusterer.java	24 Apr 2009 01:22:58 -0000	1.1
+++ Clusterer.java	7 May 2009 22:36:21 -0000	1.2
@@ -23,12 +23,6 @@
 {
     public String getName();
     
-    public double getSeedThreshold();
-    
-    public double getNeighborThreshold();
-    
-    public double getClusterThreshold();
-    
     public List<SiTrackerHit> makeHits(IDetectorElement detector);
     
     public List<SiTrackerHit> makeHits(SiSensor sensor);

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
GenericReadoutChip.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- GenericReadoutChip.java	29 Apr 2009 21:37:11 -0000	1.2
+++ GenericReadoutChip.java	7 May 2009 22:36:21 -0000	1.3
@@ -36,9 +36,9 @@
     private static Random _random = new Random();
     private static NormalDistribution _gaussian = new NormalDistributionImpl(0.0, 1.0);
     private static BinomialDistribution _binomial = new BinomialDistributionImpl(1, 1);
-    private Clusterer _clusterer;
+    private double _noise_threshold;
+    private double _neighbor_threshold;
     private GenericChannel _channel = new GenericChannel();
-    private double _capacitance;
 
     /** Creates a new instance of GenericReadoutChip */
     public GenericReadoutChip() {
@@ -65,31 +65,32 @@
     }
 
     /**
-     * Set the capacitance of the strip/pixels.  Units are fF.
+     * Set the threshold for reading out a channel.  Units are electrons.
      * 
-     * @param capacitance
+     * @param noise_threshold
      */
-    public void setCapacitance(double capacitance) {
-        _capacitance = capacitance;
+    public void setNoiseThreshold(double noise_threshold) {
+        _noise_threshold = noise_threshold;
     }
 
     /**
-     * Set the conversion between charge and ADC counts.  Units are ADC counts
-     * per fC of charge.
+     * Set the threshold for reading a channel if it's neighbor is
+     * above the noise threshold.  Units are electrons.
      *
-     * @param adc_per_fC
+     * @param neighbor_threshold
      */
-    public void setConversionConstant(double adc_per_fC) {
-        _channel.setConversionConstant(adc_per_fC);
+    public void setNeighborThreshold(double neighbor_threshold) {
+        _neighbor_threshold = neighbor_threshold;
     }
 
     /**
-     * Set the clusterer to be used for this readout chip.
+     * Set the conversion between charge and ADC counts.  Units are ADC counts
+     * per fC of charge.
      *
-     * @param _clusterer
+     * @param adc_per_fC
      */
-    public void setClusterer(Clusterer clusterer) {
-        _clusterer = clusterer;
+    public void setConversionConstant(double adc_per_fC) {
+        _channel.setConversionConstant(adc_per_fC);
     }
 
     /**
@@ -121,9 +122,7 @@
         }
 
         //  Add noise hits to the electrode data collection
-//        if (_strip_clusterer != null) {
-//            addNoise(data, electrodes);
-//        }
+        addNoise(data, electrodes);
 
         //  return the digitized charge data as a map that associates a hit
         //  channel with a list of raw data for the channel
@@ -222,14 +221,15 @@
             eldata.addCharge(noise_charge);
         }
 
-        //  Add random noise hits where the noise charge exceeds the cluster seed threshold
+        //  Add random noise hits where the noise charge exceeds the noise threshold
 
         //  Find the number of pixels/strips that are not currently hit
         int nelectrodes = electrodes.getNCells();
         int nelectrodes_empty = nelectrodes - data.size();
 
-        //  Get the seed threshold from the clusterer
-        double normalized_integration_limit = _clusterer.getSeedThreshold();
+        //  Get the noise threshold in units of the noise charge
+        double noiseRMS = _channel.computeNoise(electrodes.getCapacitance());
+        double normalized_integration_limit = _noise_threshold / noiseRMS;
 
         //  Calculate how many channels should get noise hits
         double integral = Erf.phic(normalized_integration_limit);
@@ -265,7 +265,9 @@
             neighbors.removeAll(data.keySet());
 
             nelectrodes_empty = neighbors.size();
-            normalized_integration_limit = _clusterer.getNeighborThreshold();  // We should get this from same place as clustering code
+
+            //  Get the noise threshold in units of the noise charge
+            normalized_integration_limit = _neighbor_threshold / noiseRMS;
 
             integral = Erf.phic(normalized_integration_limit);
             nchannels_throw = drawBinomial(nelectrodes_empty, integral);
@@ -336,6 +338,8 @@
 
         private double _noise_intercept = 0.;
         private double _noise_slope = 0.;
+        private double _noise_threshold = 1.;
+        private double _neighbor_threshold = 1.;
         private double _adc_per_fC = 100.;
 
         /**
@@ -366,7 +370,7 @@
         }
 
         /**
-         * Set the capacitative noise slope (in electrons / fF)
+         * Set the capacitative noise slope (in electrons / pF)
          *
          * @param noise_slope noise slope
          */
@@ -377,7 +381,7 @@
         /**
          * Return the noise in electrons for a given strip/pixel capacitance
          *
-         * @param capacitance capacitance in fF
+         * @param capacitance capacitance in pF
          * @return noise in electrons
          */
         public double computeNoise(double capacitance) {

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
Kpix.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- Kpix.java	24 Apr 2009 01:22:58 -0000	1.1
+++ Kpix.java	7 May 2009 22:36:21 -0000	1.2
@@ -36,7 +36,8 @@
     private static Random _random = new Random();
     private static NormalDistribution _gaussian = new NormalDistributionImpl(0.0,1.0);
     private static BinomialDistribution _binomial = new BinomialDistributionImpl(1,1);
-    private Clusterer _clusterer;
+    private double _noise_threshold = 4;
+    private double _neighbor_threshold = 2;
 
     // Static values and defaults: DO NOT CHANGE
     //==========================================
@@ -118,20 +119,36 @@
     public Kpix() {
     }
     
-    public void setClusterer(Clusterer clusterer)
-    {
-        _clusterer = clusterer;
-    }
-
     // ReadoutChip Interface
     public KpixChannel getChannel(int channel_number) {
         return _channel;
     }
-    
+
+    /**
+     * Set noise threshold for creating noise hits.  Units are number of sigma
+     * above the RMS noise.
+     * 
+     * @param noise_threshold
+     */
+    public void setNoiseThreshold(double noise_threshold) {
+        _noise_threshold = noise_threshold;
+    }
+
+    /**
+     * Set the threshold for reading a channel if it's neighbor is
+     * above the noise threshold.  Units are number of sigma above
+     * the RMS noise.
+     *
+     * @param neighbor_threshold
+     */
+    public void setNeighborThreshold(double neighbor_threshold) {
+        _neighbor_threshold = neighbor_threshold;
+    }
+
     public SortedMap<Integer,List<Integer>> readout(SiElectrodeDataCollection data, SiSensorElectrodes electrodes)
     {
         if (data == null) data = new SiElectrodeDataCollection();
-        if (_clusterer != null) addNoise(data,electrodes);
+        addNoise(data,electrodes);
         return digitize(data,electrodes);
     }
 
@@ -188,7 +205,7 @@
 
         int nelectrodes = electrodes.getNCells();
         int nelectrodes_empty = nelectrodes - data.size();
-        double normalized_integration_limit = _clusterer.getSeedThreshold();  // We should get this from same place as clustering code        
+        double normalized_integration_limit = _noise_threshold;
 
         double integral = normalCDF(normalized_integration_limit);
         int nchannels_throw = drawBinomial(nelectrodes_empty, integral);
@@ -230,7 +247,7 @@
             neighbors.removeAll(data.keySet());
 
             nelectrodes_empty = neighbors.size();
-            normalized_integration_limit = _clusterer.getNeighborThreshold();  // We should get this from same place as clustering code
+            normalized_integration_limit = _neighbor_threshold;
             
             integral = normalCDF(normalized_integration_limit);
             nchannels_throw = drawBinomial(nelectrodes_empty, integral);

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
PixelHitMaker.java 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- PixelHitMaker.java	30 Apr 2009 22:13:13 -0000	1.2
+++ PixelHitMaker.java	7 May 2009 22:36:21 -0000	1.3
@@ -17,7 +17,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -31,7 +30,6 @@
 import org.lcsim.detector.tracker.silicon.SiPixels;
 import org.lcsim.detector.tracker.silicon.SiSensor;
 import org.lcsim.detector.tracker.silicon.SiSensorElectrodes;
-import org.lcsim.detector.tracker.silicon.SiStrips;
 import org.lcsim.detector.tracker.silicon.SiTrackerIdentifierHelper;
 import org.lcsim.event.RawTrackerHit;
 import org.lcsim.event.SimTrackerHit;
@@ -45,11 +43,9 @@
     
     private static String _NAME = "PixelClusterer";
     
-    // Thresholds
-    double _seed_threshold = 4;     // to seed a cluster
-    double _neighbor_threshold = 2; // to add to a cluster
-    double _cluster_threshold = 3;  // to make a cluster (noise of channels is summed)
-    
+    // Clustering algorithm
+    ClusteringAlgorithm _clustering;
+
     // Absolute maximum cluster size
     int _max_cluster_npixels = 10;
     
@@ -62,33 +58,35 @@
     // Identifier helper (reset once per sensor)
     SiTrackerIdentifierHelper _sid_helper;
     
-    // Temporary maps connecting hits to pixel numbers for sake of speed (reset once per sensor)
+    // Temporary map connecting hits to pixel numbers for sake of speed (reset once per sensor)
     Map<RawTrackerHit,Integer> _pixel_map = new HashMap<RawTrackerHit,Integer>();
-    Map<Integer,RawTrackerHit> _pixel_map_inv = new HashMap<Integer,RawTrackerHit>();
     
-    /** Creates a new instance of Tracker1DHitMaker */
+    /**
+     * Create a new instance of PixelHitMaker that uses the default clustering algorithm
+     *
+     * @param simulation charge collection simulation
+     * @param readout_chip readout chip
+     */
     public PixelHitMaker(SiSensorSim simulation, ReadoutChip readout_chip)
     {
-        _simulation = simulation;
-        _readout_chip = readout_chip;
-        
-        _readout_chip.setClusterer(this);
-    }
-    
-    // Settings for Tracker1DHitMaker
-    public void setSeedThreshold(double nsigma)
-    {
-        _seed_threshold = nsigma;
+        this(simulation, readout_chip, new NearestNeighbor());
     }
     
-    public void setNeigborThreshold(double nsigma)
-    {
-        _neighbor_threshold = nsigma;
+    /**
+     * Fully qualified constructor for PixelHitMaker
+     * 
+     * @param simulation charge collection simulation
+     * @param readout_chip readout chip
+     * @param clustering clustering algorithm
+     */
+    public PixelHitMaker(SiSensorSim simulation, ReadoutChip readout_chip, ClusteringAlgorithm clustering) {
+        _simulation = simulation;
+        _readout_chip = readout_chip;
+        _clustering = clustering;
     }
-    
-    public void setClusterThreshold(double nsigma)
-    {
-        _cluster_threshold = nsigma;
+
+    public void setClusteringAlgorithm(ClusteringAlgorithm clustering_algorithm) {
+        _clustering = clustering_algorithm;
     }
     
     public void setMaxClusterSize(int max_cluster_npixels)
@@ -100,22 +98,7 @@
     {
         return _NAME;
     }
-    
-    public double getSeedThreshold()
-    {
-        return _seed_threshold;
-    }
-    
-    public double getNeighborThreshold()
-    {
-        return _neighbor_threshold;
-    }
-    
-    public double getClusterThreshold()
-    {
-        return _cluster_threshold;
-    }
-    
+        
     // Make hits for all sensors within a DetectorElement
     public List<SiTrackerHit> makeHits(IDetectorElement detector)
     {
@@ -148,7 +131,6 @@
         // Get SiTrackerIdentifierHelper for this sensor and refresh the pixel map used to increase speed
         _sid_helper = (SiTrackerIdentifierHelper)sensor.getIdentifierHelper();
         _pixel_map.clear();
-        _pixel_map_inv.clear();
         
         // Get hits for this sensor
         IReadout ro = sensor.getReadout();
@@ -163,14 +145,9 @@
             IIdentifier id = raw_hit.getIdentifier();
             int pixel_number = _sid_helper.getElectrodeValue(id);
 
-            //  Check for duplicates
-            if (_pixel_map.containsKey(raw_hit) || _pixel_map_inv.containsKey(pixel_number))
-                throw new RuntimeException("Duplicate hit or cell number");
-
             //  Add this hit to the pixel maps
             _pixel_map.put(raw_hit, pixel_number);
-            _pixel_map_inv.put(pixel_number, raw_hit);
-            
+
             // Get electrodes and check that they are pixels
             //System.out.println("proc raw hit from: " + DetectorElementStore.getInstance().find(raw_hit.getIdentifier()).get(0).getName());
             ChargeCarrier carrier = ChargeCarrier.getCarrier(_sid_helper.getSideValue(id));
@@ -200,88 +177,24 @@
     // Make hits for an electrode
     public List<SiTrackerHit> makeHits(SiSensorElectrodes electrodes, List<RawTrackerHit> raw_hits)
     {
-        //  Check that the seed threshold is at least as large as  the neighbor threshold
-        if (_seed_threshold < _neighbor_threshold)
-            throw new RuntimeException("Tracker hit clustering error: seed threshold below neighbor threshold");
 
-        //  Create a list for the clustered hits
-        List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
-
-        //  Create list of seed candidates and map showing hit status (true = available for clustering)
-        List<RawTrackerHit> cluster_seeds = new ArrayList<RawTrackerHit>();
-        Map<Integer, Boolean> clusterable = new HashMap<Integer, Boolean>();
-        
-        //  Loop over the raw hits and check if they should be added to the unclustered and/or seed lists
-        for (RawTrackerHit raw_hit : raw_hits) {
-
-            //  Get the signal/noise for this hit
-            int pixel_number = _pixel_map.get(raw_hit);
-            double signal = _readout_chip.decodeCharge(raw_hit);
-            double noise = _readout_chip.getChannel(pixel_number).computeNoise(electrodes.getCapacitance(pixel_number));
-            double SNR = signal / noise;
-
-            //  Mark this hit as available for clustering if it is above the neighbor threshold
-            clusterable.put(pixel_number, SNR > _neighbor_threshold);
-
-            //  Add this hit to the list of seeds if appropriate
-            if (SNR > _seed_threshold) cluster_seeds.add(raw_hit);
-        }
-
-        //  Now loop over the cluster seeds to form clusters
-        for (RawTrackerHit raw_hit : cluster_seeds) {
-
-            //  First check if this hit is still available for clustering
-            int raw_pixel_number = _pixel_map.get(raw_hit);
-            if (clusterable.get(raw_pixel_number)) {
-
-                //  Create a new cluster and add the hit to it
-                List<RawTrackerHit> cluster = new ArrayList<RawTrackerHit>();
-
-                //  Create a queue to hold hits whose neighbors need to be checked for inclusion
-                LinkedList<RawTrackerHit> unchecked = new LinkedList<RawTrackerHit>();
-
-                //  Add the seed hit and mark it as unavailable for clustering
-                unchecked.addLast(raw_hit);
-                clusterable.put(raw_pixel_number, false);
-
-                //  Check the neighbors of hits added to the cluster
-                while (unchecked.size() > 0) {
-
-                    //  Pull the next hit off the queue and add it to the cluster
-                    RawTrackerHit clusteredhit = unchecked.removeFirst();
-                    cluster.add(clusteredhit);
+        //  Call the clustering algorithm to make clusters
+        List<List<RawTrackerHit>> cluster_list = _clustering.findClusters(electrodes, _readout_chip, raw_hits);
 
-                    //  Get the neigbor cells
-                    Set<Integer> neighbor_cells = electrodes.getNearestNeighborCells(_pixel_map.get(clusteredhit));
-
-                    //   Now loop over the neighbors and see if we can add them to the cluster
-                    for (int cell : neighbor_cells) {
-
-                        //  First see if this neighbor cell is in our clusterable hit map
-                        if (clusterable.containsKey(cell)) {
-
-                           //  Now check if this neighbor cell is still available for clustering
-                           if (clusterable.get(cell)) {
+        //  Create an empty list for the pixel hits to be formed from clusters
+        List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
 
-                               //  Add hit to the list of unchecked cluster hits and mark it unavailable for clustering
-                               unchecked.addLast(_pixel_map_inv.get(cell));
-                               clusterable.put(cell, false);
-                           }
-                        }
-                    }
-                }
+        //  Make a pixel hit from this cluster
+        for (List<RawTrackerHit> cluster : cluster_list) {
 
-                // Make a TrackerHit from the cluster if it meets max cluster size requirement
-                if (cluster.size() <= _max_cluster_npixels)
-                {
-                    SiTrackerHitPixel hit = makeTrackerHit(cluster,electrodes);
+            // Make a TrackerHit from the cluster if it meets max cluster size requirement
+            if (cluster.size() <= _max_cluster_npixels)
+            {
+                SiTrackerHitPixel hit = makeTrackerHit(cluster,electrodes);
                     
-                    // Add to readout and to list of hits
-                    ((SiSensor)electrodes.getDetectorElement()).getReadout().addHit(hit);
-                    hits.add(hit);
-                }
-                
-                
+                // Add to readout and to list of hits
+                ((SiSensor)electrodes.getDetectorElement()).getReadout().addHit(hit);
+                hits.add(hit);
             }
         }
         
@@ -335,20 +248,7 @@
             position = VecOp.add(position,VecOp.mult(signal,positions.get(ipixel)));
         }
         position = VecOp.mult(1/total_charge,position);
-        
-//        double total_charge = 0;
-//        Hep3Vector position = new BasicHep3Vector(0,0,0);
-//        
-//        for (RawTrackerHit hit : cluster)
-//        {
-//            int strip_number = _strip_map.get(hit);
-//            double signal = _readout_chip.decodeCharge(hit);
-//            
-//            total_charge += signal;
-//            position = VecOp.add(position,VecOp.mult(signal,((SiStrips)electrodes).getStripCenter(strip_number)));
-//        }
-//        position = VecOp.mult(1/total_charge,position);
-        
+                
         // Put position in sensor coordinates
         electrodes.getParentToLocal().inverse().transform(position);
         
@@ -400,19 +300,6 @@
         
         return covariance_global;
         
-//        BasicHep3Matrix rotation_matrix = (BasicHep3Matrix)electrodes.getLocalToGlobal().getRotation().getRotationMatrix();
-//        BasicHep3Matrix rotation_matrix_transposed = new BasicHep3Matrix(rotation_matrix);
-//        rotation_matrix_transposed.transpose();
-//
-////        System.out.println("Rotation matrix: \n"+rotation_matrix);
-////        System.out.println("Rotation matrix transposed: \n"+rotation_matrix_transposed);
-////        System.out.println("Local covariance matrix: \n"+covariance);
-//
-//        BasicHep3Matrix covariance_global = (BasicHep3Matrix)VecOp.mult(rotation_matrix,VecOp.mult(covariance,rotation_matrix_transposed));
-//
-////        System.out.println("Global covariance matrix: \n"+covariance_global);
-//
-//        return new SymmetricMatrix((Matrix)covariance_global);
     }
 
     private double getXResolution(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes)
@@ -488,8 +375,6 @@
         return measured_resolution;
 
     }
-
-    
     
     private double getEnergy(List<RawTrackerHit> cluster)
     {
@@ -505,5 +390,4 @@
         return total_charge * DopedSilicon.ENERGY_EHPAIR;
     }
     
-    
 }

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
ReadoutChip.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- ReadoutChip.java	24 Apr 2009 01:22:58 -0000	1.1
+++ ReadoutChip.java	7 May 2009 22:36:21 -0000	1.2
@@ -20,13 +20,12 @@
  */
 public interface ReadoutChip
 {
-    public void setClusterer(Clusterer clusterer);
-    
     public SortedMap<Integer,List<Integer>> readout(SiElectrodeDataCollection data, SiSensorElectrodes electrodes);
 
     public ReadoutChannel getChannel(int channel_number);
     
     public double decodeCharge(RawTrackerHit hit);
+
     public int decodeTime(RawTrackerHit hit);
     
     public interface ReadoutChannel

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
StripHitMaker.java 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- StripHitMaker.java	24 Apr 2009 01:22:58 -0000	1.1
+++ StripHitMaker.java	7 May 2009 22:36:21 -0000	1.2
@@ -42,11 +42,9 @@
 {
     
     private static String _NAME = "StripClusterer";
-    
-    // Thresholds
-    double _seed_threshold = 4;     // to seed a cluster
-    double _neighbor_threshold = 2; // to add to a cluster
-    double _cluster_threshold = 3;  // to make a cluster (noise of channels is summed)
+
+    // Clustering algorithm
+    ClusteringAlgorithm _clustering;
     
     // Number of strips beyond which charge is averaged on center strips
     int _max_noaverage_nstrips = 4;
@@ -66,31 +64,13 @@
     // Temporary map connecting hits to strip numbers for sake of speed (reset once per sensor)
     Map<RawTrackerHit,Integer> _strip_map = new HashMap<RawTrackerHit,Integer>();
     
-    /** Creates a new instance of Tracker1DHitMaker */
+    /** Creates a new instance of StripHitMaker */
     public StripHitMaker(SiSensorSim simulation, ReadoutChip readout_chip)
     {
         _simulation = simulation;
         _readout_chip = readout_chip;
-        
-        _readout_chip.setClusterer(this);
-    }
-    
-    // Settings for Tracker1DHitMaker
-    public void setSeedThreshold(double nsigma)
-    {
-        _seed_threshold = nsigma;
-    }
-    
-    public void setNeigborThreshold(double nsigma)
-    {
-        _neighbor_threshold = nsigma;
-    }
-    
-    public void setClusterThreshold(double nsigma)
-    {
-        _cluster_threshold = nsigma;
     }
-    
+        
     public void setCentralStripAveragingThreshold(int max_noaverage_nstrips)
     {
         _max_noaverage_nstrips = max_noaverage_nstrips;
@@ -106,21 +86,6 @@
         return _NAME;
     }
     
-    public double getSeedThreshold()
-    {
-        return _seed_threshold;
-    }
-    
-    public double getNeighborThreshold()
-    {
-        return _neighbor_threshold;
-    }
-    
-    public double getClusterThreshold()
-    {
-        return _cluster_threshold;
-    }
-    
     // Make hits for all sensors within a DetectorElement
     public List<SiTrackerHit> makeHits(IDetectorElement detector)
     {
@@ -196,89 +161,30 @@
     // Make hits for an electrode
     public List<SiTrackerHit> makeHits(SiSensorElectrodes electrodes, List<RawTrackerHit> raw_hits)
     {
-        
-//            System.out.println("Clustering electrodes: "+electrodes_id);
-        
+
+        //  Call the clustering algorithm to make clusters
+        List<List<RawTrackerHit>> cluster_list = _clustering.findClusters(electrodes, _readout_chip, raw_hits);
+
+        //  Create an empty list for the pixel hits to be formed from clusters
         List<SiTrackerHit> hits = new ArrayList<SiTrackerHit>();
-        
-        List<RawTrackerHit> unclustered_rawhits = new ArrayList<RawTrackerHit>(raw_hits);
-        
-        for (RawTrackerHit raw_hit : raw_hits)
-        {
-            
-            int strip_number = _strip_map.get(raw_hit);
-            double signal = _readout_chip.decodeCharge(raw_hit);
-            double noise = _readout_chip.getChannel(strip_number).computeNoise(electrodes.getCapacitance(strip_number));
-            
-            if (signal/noise > _seed_threshold && unclustered_rawhits.contains(raw_hit))
+
+        //  Make a pixel hit from this cluster
+        for (List<RawTrackerHit> cluster : cluster_list) {
+
+            // Make a TrackerHit from the cluster if it meets max cluster size requirement
+            if (cluster.size() <= _max_cluster_nstrips)
             {
-                
-//                    System.out.println("Creating new cluster, # Raw hits on electrodes is: "+hits.size());
-                
-                List<RawTrackerHit> cluster = new ArrayList<RawTrackerHit>();
-                List<RawTrackerHit> clustered_hits = new ArrayList<RawTrackerHit>();
-                
-                clustered_hits.add(raw_hit);
-                
-                while (clustered_hits.size() != 0)
-                {
-                    cluster.addAll(clustered_hits);
-                    unclustered_rawhits.removeAll(clustered_hits);
-                    clustered_hits = neighborHits(clustered_hits,unclustered_rawhits,electrodes);
-                    
-//                        System.out.println("    Cluster size:  "+cluster.size());
-//                        System.out.println("        # Unclustered hits:  "+unclustered_hits.size());
-//                        System.out.println("        # neighbors found:  "+clustered_hits.size());
-                }
-                
-//                if (cluster.size() > 10)
-//                {
-//                    System.out.println("Cluster size: "+cluster.size());
-//                }
-                
-                // Make a TrackerHit from the cluster if it meets max cluster size requirement
-                if (cluster.size() <= _max_cluster_nstrips)
-                {
-                    SiTrackerHitStrip1D hit = makeTrackerHit(cluster,electrodes);
-                    
-                    // Add to readout and to list of hits
-                    ((SiSensor)electrodes.getDetectorElement()).getReadout().addHit(hit);
-                    hits.add(hit);
-                }
-                
-                
+                SiTrackerHitStrip1D hit = makeTrackerHit(cluster,electrodes);
+
+                // Add to readout and to list of hits
+                ((SiSensor)electrodes.getDetectorElement()).getReadout().addHit(hit);
+                hits.add(hit);
             }
         }
-        
+
         return hits;
     }
-    
-    
-    // Find the hits neigboring a cluster
-    private List<RawTrackerHit> neighborHits(List<RawTrackerHit> clustered_hits, List<RawTrackerHit> unclustered_hits,
-            SiSensorElectrodes electrodes)
-    {
-        List<RawTrackerHit> neighbor_hits = new ArrayList<RawTrackerHit>();
-        
-        for (RawTrackerHit seed_hit : clustered_hits)
-        {
-            Set<Integer> neighbor_cells = electrodes.getNearestNeighborCells(_strip_map.get(seed_hit));
-            for (RawTrackerHit hit : unclustered_hits)
-            {
-                int strip_number = _strip_map.get(hit);
-                double signal = _readout_chip.decodeCharge(hit);
-                double noise = _readout_chip.getChannel(strip_number).computeNoise(electrodes.getCapacitance(strip_number));
-                
-                if (neighbor_cells.contains(_strip_map.get(hit)) && signal/noise > _neighbor_threshold)
-                {
-                    neighbor_hits.add(hit);
-                }
-            }
-        }
-        return neighbor_hits;
-    }
-    
-    
+              
     //Make the hit
     private SiTrackerHitStrip1D makeTrackerHit(List<RawTrackerHit> cluster, SiSensorElectrodes electrodes)
     {
CVSspam 0.2.8