Print

Print


Commit in lcsim/src/org/lcsim/recon/tracking/digitization/sisim on MAIN
NearestNeighborRMS.java+259added 1.1
(TKN) Nearest neigbor clustering with RMS noise thresholds.  Includes threshold on total cluster charge.

lcsim/src/org/lcsim/recon/tracking/digitization/sisim
NearestNeighborRMS.java added at 1.1
diff -N NearestNeighborRMS.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ NearestNeighborRMS.java	29 Mar 2010 09:36:08 -0000	1.1
@@ -0,0 +1,259 @@
+/*
+ * NearestNeighborRMS.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 RMS noise of each electrode.
+ *
+ * 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 Tim Nelson (adapted from NearestNeighbor code of Rich Partridge)
+ */
+public class NearestNeighborRMS implements ClusteringAlgorithm {
+
+    private static String _NAME = "NearestNeighborRMS";
+    private double _seed_threshold;
+    private double _neighbor_threshold;
+    private double _cluster_threshold;
+
+    /**
+     * Instantiate NearestNeighborRMS 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.
+     * Cluster threshold is minimum charge of the entire cluster.
+     * All thresholds are in units of RMS noise of the channel(s).
+     *
+     * @param seed_threshold seed threhold
+     * @param neighbor_threshold neighbor threshold
+     * @param cluster_threshold cluster threshold
+     */
+    public NearestNeighborRMS(double seed_threshold, double neighbor_threshold, double cluster_threshold) {
+        _seed_threshold = seed_threshold;
+        _neighbor_threshold = neighbor_threshold;
+        _cluster_threshold = cluster_threshold;
+    }
+
+    /**
+     * Instantiate NearestNeighborRMS with default thresholds:
+     *
+     * seed_threshold = 4*RMS noise
+     * neighbor_threhold = 3*RMS noise
+     * cluster_threshold = 4*RMS noise
+     */
+    public NearestNeighborRMS() {
+        this(4.0, 3.0, 4.0);
+    }
+
+    /**
+     * Set the seed threshold.  Units are RMS noise.
+     *
+     * @param seed_threshold seed threshold
+     */
+    public void setSeedThreshold(double seed_threshold) {
+        _seed_threshold = seed_threshold;
+    }
+
+    /**
+     * Set the neighbor threshold.  Units are RMS noise.
+     *
+     * @param neighbor_threshold neighbor threshold
+     */
+    public void setNeighborThreshold(double neighbor_threshold) {
+        _neighbor_threshold = neighbor_threshold;
+    }
+
+    /**
+     * Set the cluster threshold.  Units are RMS noise.
+     *
+     * @param cluster_threshold cluster threshold
+     */
+    public void setClusterThreshold(double cluster_threshold) {
+        _cluster_threshold = cluster_threshold;
+    }
+
+    /**
+     * Return the seed threshold.  Units are RMS noise.
+     *
+     * @return seed threshold
+     */
+    public double getSeedThreshold() {
+        return _seed_threshold;
+    }
+
+    /**
+     * Return the neighbor threshold.  Units are RMS noise.
+     *
+     * @return neighbor threshold
+     */
+    public double getNeighborThreshold() {
+        return _neighbor_threshold;
+    }
+
+    /**
+     * Return the cluster threshold.  Units are RMS noise.
+     *
+     * @return cluster threshold
+     */
+    public double getClusterThreshold() {
+        return _cluster_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 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
+        int mapsize = 2 * raw_hits.size();
+        Map<Integer, Boolean> clusterable = new HashMap<Integer, Boolean>(mapsize);
+        Map<RawTrackerHit, Integer> hit_to_channel = new HashMap<RawTrackerHit, Integer>(mapsize);
+        Map<Integer, RawTrackerHit> channel_to_hit = new HashMap<Integer, RawTrackerHit>(mapsize);
+
+        //  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
+            SiTrackerIdentifierHelper sid_helper = (SiTrackerIdentifierHelper) raw_hit.getIdentifierHelper();
+            IIdentifier id = raw_hit.getIdentifier();
+            int channel_number = sid_helper.getElectrodeValue(id);
+
+            //  Check for duplicate RawTrackerHit
+            if (hit_to_channel.containsKey(raw_hit)) {
+                throw new RuntimeException("Duplicate hit: "+id.toString());
+            }
+
+            //  Check for duplicate RawTrackerHits or channel numbers
+            if (channel_to_hit.containsKey(channel_number)) {
+                throw new RuntimeException("Duplicate channel number: "+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
+            double signal = readout_chip.decodeCharge(raw_hit);
+            double noiseRMS = readout_chip.getChannel(channel_number).computeNoise(electrodes.getCapacitance(channel_number));
+
+            //  Mark this hit as available for clustering if it is above the neighbor threshold
+            clusterable.put(channel_number, signal/noiseRMS >= _neighbor_threshold);
+
+            //  Add this hit to the list of seeds if it is above the seed threshold
+            if (signal/noiseRMS >= _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>();
+            double cluster_signal = 0.;
+            double cluster_noise_squared = 0.;
+
+            //  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));
+                cluster_signal += readout_chip.decodeCharge(channel_to_hit.get(clustered_cell));
+                cluster_noise_squared += Math.pow(readout_chip.getChannel(clustered_cell).computeNoise(electrodes.getCapacitance(clustered_cell)),2);
+
+                //  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) {
+
+                    //  Get the status of this channel
+                    Boolean addhit = clusterable.get(channel);
+
+                    //  If the map entry is null, there is no raw hit for this channel
+                    if (addhit == null) continue;
+
+                    //  Check if this neighbor channel is still available for clustering
+                    if (!addhit) continue;
+
+                    //  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, check cluster threshold and add it to the list of clusters
+            if (cluster.size() > 0 &&
+                cluster_signal/Math.sqrt(cluster_noise_squared) > _cluster_threshold)
+            {
+                cluster_list.add(cluster);
+            }
+
+        }  //  End of loop over seeds
+
+        //  Finished finding clusters
+        return cluster_list;
+    }
+}
CVSspam 0.2.8