Commit in lcsim/src/org/lcsim/recon/cluster/clumpfinder on MAIN
ClumpFinder.java+170added 1.1
HighHitDensityDecision.java+85added 1.1
+255
2 added files
Find dense clumps

lcsim/src/org/lcsim/recon/cluster/clumpfinder
ClumpFinder.java added at 1.1
diff -N ClumpFinder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ClumpFinder.java	17 Jan 2006 00:11:05 -0000	1.1
@@ -0,0 +1,170 @@
+package org.lcsim.recon.cluster.clumpfinder;
+
+import java.lang.String;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.util.Driver;
+import org.lcsim.event.Cluster;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.IDDecoder;
+import org.lcsim.util.decision.*;
+import org.lcsim.recon.cluster.util.ClusterSizeDecision;
+
+/**
+ * A Driver which finds dense clumps within clusters.
+ * Each event, it reads in a List<Cluster> from the EventHeader.
+ * For each Cluster in that list, it tries to find dense
+ * clumps. Currently, clumps are defined as contiguous sets of
+ * 6+ hits where the local hit density (in a 5x5x3 block) is 7/75
+ * or more for each hit. This is hard-coded at the moment, but
+ * should become a user-definable in a later version.
+ * 
+ * @version $Id: ClumpFinder.java,v 1.1 2006/01/17 00:11:05 mcharles Exp $
+ */
+
+public class ClumpFinder extends Driver
+{
+    protected String m_inputHitMapName;
+    protected String m_outputClusterListName;
+    protected String m_outputHitMapName;
+    protected DecisionMakerSingle<CalorimeterHit> m_hitDecision;
+    protected DecisionMakerSingle<CalorimeterHit> m_seedDecision;
+    protected DecisionMakerSingle<Cluster> m_clumpDecision;
+
+    /**
+     * Constructor.
+     * @param clustersName Name of the input List<Cluster> in the event
+     * @param trackSegmentsName Name of the map which gives a list of track segments for each Cluster. These will not be used in clump-finding.
+     * @param outputName Name to use for the output map which will give a list of clumps for each Cluster.
+     */
+    public ClumpFinder(String inputHitMap, String outputClusterList, String outputHitMap)
+    {
+	m_inputHitMapName = inputHitMap;
+	m_outputClusterListName = outputClusterList;
+	m_outputHitMapName = outputHitMap;
+
+	m_hitDecision = new DummyDecisionMakerSingle<CalorimeterHit> (); // Default: All hits are valid
+	m_seedDecision = new DummyDecisionMakerSingle<CalorimeterHit> (); // Default: All seeds are valid
+	m_clumpDecision = new ClusterSizeDecision(6); // Default: Clumps must have >= 6 hits
+    }
+
+
+    /**
+     * Find clumps within each cluster, and write them back to the event.
+     */
+    public void process(EventHeader event) 
+    {
+	// Read in the inputs
+	Map<Long,CalorimeterHit> inputHitMap = (Map<Long,CalorimeterHit>) (event.get(m_inputHitMapName));
+
+	// Outputs:
+	Vector<Cluster> outputClusterList = new Vector<Cluster>();
+	Map<Long,CalorimeterHit> outputHitMap = new HashMap<Long,CalorimeterHit>(inputHitMap); // initially cloned
+
+	// Clone the input hitmap to give a list of unused hits we can edit:
+	ListFilter<CalorimeterHit> hitFilter = new ListFilter<CalorimeterHit> (m_hitDecision);
+	List<CalorimeterHit> inputHits = hitFilter.filterList(inputHitMap.values());
+	// Filter these again, require high local density:
+	ListFilter<CalorimeterHit> densityFilter = new ListFilter<CalorimeterHit> (new HighHitDensityDecision(inputHits));
+	List<CalorimeterHit> unusedHits = densityFilter.filterList(inputHits);
+	// Apply some pre-filtering on these with a ListFilter to get a list of seeds
+	ListFilter<CalorimeterHit> seedFilter = new ListFilter<CalorimeterHit> (m_seedDecision);
+	List<CalorimeterHit> seedHits = seedFilter.filterList(unusedHits);
+
+	// For each seed hit, try to make a clump
+	for (CalorimeterHit seedHit : seedHits) {
+	    // This seed hit might already have been removed if it was used in a previous
+	    // clump, so we need to verify it's still there.
+	    if (unusedHits.contains(seedHit)) {
+		Cluster clump = makeClump(seedHit, unusedHits);
+		if (m_clumpDecision.valid(clump)) {
+		    // Accept this clump -- add it to the output list and remove its hits from consideration
+		    outputClusterList.add(clump);
+		    for (CalorimeterHit hitInClump : clump.getCalorimeterHits()) {
+			unusedHits.remove(hitInClump);
+			outputHitMap.remove(hitInClump.getCellID());
+		    }
+		}
+	    }
+	}
+
+	// Write out:
+	event.put(m_outputHitMapName, outputHitMap);
+	event.put(m_outputClusterListName, outputClusterList);
+    }
+
+    /**
+     * Interal routine: make a clump.
+     *
+     * @param seedHit    The first hit in the clump
+     * @param unusedHits The list of hits which may be added to the clump. This contains seedHit.
+     */
+    protected Cluster makeClump(CalorimeterHit seedHit, List<CalorimeterHit> unusedHits) 
+    {
+	// This we expect to be over-ridden. Might even farm it out to
+	// an external class. For now, here is a default.
+
+	BasicCluster clump = new BasicCluster();
+	Set<CalorimeterHit> hitsUsedInClump = new HashSet<CalorimeterHit>();
+	clump.addHit(seedHit);
+	hitsUsedInClump.add(seedHit);
+	recursivelyAddNeighbours(seedHit, clump, unusedHits, hitsUsedInClump);
+	return clump;
+    }
+
+    /**
+     * Internal routine: add hits to a clump.
+     *
+     * @param seedHit         Try to add neighbours of this hit
+     * @param clump           The clump
+     * @param unusedHits      The list of hits which may be added to the clump. This contains seedHit.
+     * @param hitsUsedInClump The subset of unusedHits which have already been added to the clump.
+     */
+    protected void recursivelyAddNeighbours(CalorimeterHit seedHit, BasicCluster clump, List<CalorimeterHit> unusedHits, Set<CalorimeterHit> hitsUsedInClump)
+    {
+	org.lcsim.geometry.IDDecoder id = seedHit.getIDDecoder();
+	org.lcsim.geometry.CalorimeterIDDecoder idCAL = (org.lcsim.geometry.CalorimeterIDDecoder) (id);
+	idCAL.setID(seedHit.getCellID());
+	if (!idCAL.supportsNeighbours()) {
+	    throw new AssertionError("Can't get neighbours!");
+	} else {
+	    // Parameters (hard-coded for now);
+	    int deltaLayer = 1;
+	    int deltaTheta = 1;
+	    int deltaPhi = 1;
+	    // Find all hits from [unusedHits] within range:
+	    long[] neighbourIDs = idCAL.getNeighbourIDs(deltaLayer, deltaTheta, deltaPhi);
+	    List<CalorimeterHit> neighbourHits = new Vector<CalorimeterHit>();
+	    // Look for cells which
+	    //   (a) are neighbours
+	    //   (b) are in the list "unusedHit", i.e. have a hit and aren't already in a clump/track/etc
+	    //   (c) aren't in the set "hitsUsedInClump", to avoid double-counting
+	    for (long neighbourID : neighbourIDs) {
+		for (CalorimeterHit unusedHit : unusedHits) {
+		    if (unusedHit.getCellID() == neighbourID) {
+			if ( ! hitsUsedInClump.contains(unusedHit) ) {
+			    neighbourHits.add(unusedHit);
+			    break;
+			}
+		    }
+		}
+	    }
+	    for (CalorimeterHit acceptedNeighbourHit : neighbourHits) {
+		// Add this to the clump:
+		clump.addHit(acceptedNeighbourHit);
+		hitsUsedInClump.add(acceptedNeighbourHit);
+	    }
+	    for (CalorimeterHit acceptedNeighbourHit : neighbourHits) {
+		// Add its neighbours....
+		recursivelyAddNeighbours(acceptedNeighbourHit, clump, unusedHits, hitsUsedInClump);
+	    }
+	}
+    }
+}

lcsim/src/org/lcsim/recon/cluster/clumpfinder
HighHitDensityDecision.java added at 1.1
diff -N HighHitDensityDecision.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ HighHitDensityDecision.java	17 Jan 2006 00:11:05 -0000	1.1
@@ -0,0 +1,85 @@
+package org.lcsim.recon.cluster.clumpfinder;
+
+import java.lang.String;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.util.Driver;
+import org.lcsim.event.Cluster;
+import org.lcsim.recon.cluster.util.BasicCluster;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.geometry.IDDecoder;
+
+import org.lcsim.util.decision.*;
+
+/**
+ * A DecisionMaker for CalorimeterHit objects which requires them to
+ * have a high local hit density. Right now the values are hard-coded.
+ * Eventually this should be made more flexible and moved outside
+ * the "structural" package.
+ *
+ * @version $Id: HighHitDensityDecision.java,v 1.1 2006/01/17 00:11:05 mcharles Exp $
+ */
+
+public class HighHitDensityDecision implements DecisionMakerSingle<CalorimeterHit> 
+{
+    /**
+     * Constructor. 
+     *
+     * @param hits The list of hits to be used for the local density calcualtion
+     */
+    public HighHitDensityDecision(Collection<CalorimeterHit> hits) {
+	// Initialize
+	m_hitIDSet = new HashSet<Long> ();
+	for (CalorimeterHit hit : hits) {
+	    m_hitIDSet.add(new Long(hit.getCellID()));
+	}
+    }
+    
+    /**
+     * Check if the CalorimeterHit has a high local hit density.
+     * Currently hard-coded to look in a 5x5x3 grid and require
+     * at least 6 other hits present.
+     */
+    public boolean valid(CalorimeterHit seedHit) 
+    {
+	// Find hits within m_dist:
+	org.lcsim.geometry.IDDecoder id = seedHit.getIDDecoder();
+	org.lcsim.geometry.CalorimeterIDDecoder idCAL = (org.lcsim.geometry.CalorimeterIDDecoder) (id);
+	idCAL.setID(seedHit.getCellID());
+	if (!idCAL.supportsNeighbours()) {
+	    throw new AssertionError("Can't get neighbours!");
+	} else {
+	    // Parameters (hard-coded for now);
+	    int deltaLayer = 1;
+	    int deltaTheta = 2;
+	    int deltaPhi = 2;
+	    int minNeighbours = 6;
+	    // Find all hits from [unusedHits] within range:
+	    long[] neighbourIDs = idCAL.getNeighbourIDs(deltaLayer, deltaTheta, deltaPhi);
+	    Set<Long> acceptedNeighbourIDs = new HashSet<Long>();
+	    for (long neighbourID : neighbourIDs) {
+		if (m_hitIDSet.contains(new Long(neighbourID))) {
+		    acceptedNeighbourIDs.add(neighbourID);
+		}
+	    }
+	    // Were there enough?
+	    if (acceptedNeighbourIDs.size() >= minNeighbours) {
+		// Accept this
+		return true;
+	    } else {
+		// Reject this
+		return false;
+	    }
+	}
+    }
+    
+    protected Set<Long> m_hitIDSet = null;
+
+}
CVSspam 0.2.8