Commit in java/trunk/hps-java/src/main/java/org/lcsim/hps/recon/ecal on MAIN
CTPCalorimeterClusterer.java+106-202332 -> 333
fix bugs, change behavior to work correctly with readout and trigger drivers

java/trunk/hps-java/src/main/java/org/lcsim/hps/recon/ecal
CTPCalorimeterClusterer.java 332 -> 333
--- java/trunk/hps-java/src/main/java/org/lcsim/hps/recon/ecal/CTPCalorimeterClusterer.java	2014-03-21 17:25:37 UTC (rev 332)
+++ java/trunk/hps-java/src/main/java/org/lcsim/hps/recon/ecal/CTPCalorimeterClusterer.java	2014-03-21 21:37:58 UTC (rev 333)
@@ -2,7 +2,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;
@@ -24,7 +23,7 @@
  * For a hit to be a cluster center, it is required to have an energy
  * above some tunable minimum threshold. Additionally, the hit must be
  * a local maximum with respect to its neighbors and itself over a
- * tunable (default 4) clock cycles. Hits that pass these checks are
+ * tunable (default 2) clock cycles. Hits that pass these checks are
  * then required to additional have a total cluster energy that exceeds
  * another tunable minimum threshold.
  * 
@@ -72,22 +71,13 @@
     /**
      * <b>clusterWindow</b><br/><br/>
      * <code>private int <b>clusterWindow</b></code><br/><br/>
-     * Indicates the number of clock cycles before and after a given
-     * cycle that should be considered when checking if a cluster is
-     * a local maximum in space-time.
+     * Indicates the number of FADC clock cycles (each cycle is 4 ns) before and
+     * after a given cycle that should be considered when checking if a cluster
+     * is a local maximum in space-time.
      */
     int clusterWindow = 2;
     
     /**
-     * <b>eventBuffer</b><br/><br/>
-     * <code>private LinkedList<EventHeader> <b>eventBuffer</b></code><br/><br/>
-     * Stores the <code>EventHeader</code> objects that occurred within
-     * the cluster window so that clusters may be attached to the event
-     * in which the seed hit occurred.
-     */
-    private LinkedList<EventHeader> eventBuffer;
-    
-    /**
      * <b>hitBuffer</b><br/><br/>
      * <code>private LinkedList<List<CalorimeterHit>> <b>hitBuffer</b></code><br/><br/>
      * Stores a set of all the hits occurring in each clock cycle for
@@ -119,16 +109,16 @@
      * cluster center. Hits with energy less than this value will
      * be ignored.
      */
-    double seedEnergyThreshold = 0.0;
-    
+    double seedEnergyThreshold = 0.05;
+
     /**
-     * <b>validClusterCrystals</b><br/><br/>
-     * <code>private Set<Long> <b>validClusterCrystals</b></code><br/><br/>
-     * Contains the <code>long</code> crystal ID of every crystal that
-     * is a valid cluster center.
+     * <b>addEnergyThreshold</b><br/><br/>
+     * <code>private double <b>addEnergyThreshold</b></code><br/><br/>
+     * The minimum energy required for a hit to be added to a cluster. Hits with
+     * energy less than this value will be ignored.
      */
-    private Set<Long> validClusterCrystals = null;
-    
+    double addEnergyThreshold = 0.03;
+
     /**
      * <b>detectorChanged</b><br/><br/>
      * <code>public void <b>detectorChanged</b>(Detector detector)</code><br/><br/>
@@ -147,65 +137,9 @@
         
         // Get a map to associate crystals with their neighbors.
         neighborMap = calorimeter.getNeighborMap();
-        
-        // Store the crystals that are allowed to be cluster centers.
-        validClusterCrystals = new HashSet<Long>();
-        
-        // Populate the list of valid cluster centers.
-        for (Long cellID : neighborMap.keySet()) {
-        	// Store whether the current crystal is a valid cluster center.
-            boolean isValidCenter = true;
-            
-            // Get the set of neighbors for the current crystal.
-            Set<Long> neighbors = neighborMap.get(cellID);
-            
-            // Sort over the list of neighbors.
-            for (Long neighborID : neighbors) {
-            	// Get the neighbor's list of neighbors as well as itself.
-                Set<Long> neighborNeighbors = new HashSet<Long>();
-                neighborNeighbors.addAll(neighborMap.get(neighborID));
-                neighborNeighbors.add(neighborID);
-                
-                // If the current crystal's neighbors include all of
-                // one of its neighbor's neighbors, then it is an edge
-                // crystal and is not a valid center for clusters.
-                if (neighborNeighbors.containsAll(neighbors)) {
-                    isValidCenter = false;
-                    break;
-                }
-            }
-            
-            // If the current crystal survived the above test, it is
-            // a valid cluster center. Add it to the list.
-            if (isValidCenter) { validClusterCrystals.add(cellID); }
-        }
     }
     
     /**
-     * <b>endOfData</b><br/><br/>
-     * <code>public void <b>endOfData</b>()</code><br/><br/>
-     * Empties the remaining events from the event buffer and processes
-     * any remaining clusters.
-     */
-    public void endOfData() {
-    	// At the end of the data run, not all filled events in the hit
-    	// buffer will have been processed. We add additional empty
-    	// events to the end of the event buffer and continue to process
-    	// events until all the remaining legitimate events have been
-    	// processed.
-    	for(int i = 0; i < clusterWindow; i++) {
-        	// Remove the last event from the hit buffer a blank one.
-        	hitBuffer.removeLast();
-        	hitBuffer.addFirst(new HashMap<Long, CalorimeterHit>(0));
-        	eventBuffer.removeLast();
-        	eventBuffer.addFirst(null);
-        	
-        	// Process the event.
-        	processEvent();
-    	}
-    }
-    
-    /**
      * <b>getClusters</b><br/><br/>
      * <code>public List<HPSEcalCluster> <b>getClusters</b>()</code><br/><br/>
      * Generates a list of clusters from the current hit buffer. The
@@ -225,11 +159,8 @@
     	// For a hit to be a cluster center, it must be a local maximum
     	// both with respect to its neighbors and itself both in the
     	// present time and at all times within the event buffer.
+        seedLoop:
     	for(Long currentID : currentHits.keySet()) {
-    		// If this hit is not a valid cluster center, we do not
-    		// need to perform any additional checks.
-    		if(validClusterCrystals.contains(currentID)) { continue; }
-    		
     		// Get the actual hit object.
     		CalorimeterHit currentHit = currentHits.get(currentID);
     		
@@ -238,91 +169,68 @@
     		
     		// If the hit energy is lower than the minimum threshold,
     		// then we immediately reject this hit as a possible cluster.
-    		if(currentEnergy < seedEnergyThreshold) { continue; }
+    		if(currentEnergy < seedEnergyThreshold) { continue seedLoop; }
     		
-    		// Store the cluster energy for the potential cluster as we
-    		// sort through the buffer.
-    		double clusterEnergy = 0.0;
+    		// Store the crystals that are part of this potential cluster.
+            HPSEcalCluster cluster = new HPSEcalCluster(currentHit);
+            cluster.addHit(currentHit);
     		
-    		// Store the crystals that are part of this cluster.
-    		Set<CalorimeterHit> clusterComponentHits = new HashSet<CalorimeterHit>();
-    		
     		// Get the set of neighbors for this hit.
     		Set<Long> neighbors = neighborMap.get(currentHit.getCellID());
     		
-    		// Store whether the current hit is a cluster center.
-    		boolean isCluster = true;
-    		
     		// Sort through each event stored in the buffer.
-    		for(Map<Long, CalorimeterHit> bufferHits : hitBuffer) {
-    			// Get the hit energy at the current hit's position in
-    			// the buffer, if it exists.
-    			double bufferHitEnergy = 0.0;
-    			CalorimeterHit bufferHit = bufferHits.get(currentID);
-    			if(bufferHit != null) { bufferHitEnergy = bufferHit.getRawEnergy(); }
+            addLoop:
+            for (Map<Long, CalorimeterHit> bufferHits : hitBuffer) {
+                // Get the hit energy at the current hit's position in
+                // the buffer, if it exists.
+                CalorimeterHit bufferHit = bufferHits.get(currentID);
+                if (bufferHit != null) {
+                    double bufferHitEnergy = bufferHit.getRawEnergy();
+
+                    // Check to see if the hit at this point in the buffer
+                    // is larger than then original hit. If it is, we may
+                    // stop the comparison because this is not a cluster.
+                    if (bufferHitEnergy > currentEnergy) {
+                        continue seedLoop;
+                    } // If the buffer hit is smaller, then add its energy
+                    // to the cluster total energy.
+                    else {
+                        if (bufferHit != currentHit && bufferHitEnergy > addEnergyThreshold) {
+                            cluster.addHit(bufferHit);
+                        }
+                    }
+                }
     			
-    			// Check to see if the hit at this point in the buffer
-    			// is larger than then original hit. If it is, we may
-    			// stop the comparison because this is not a cluster.
-    			if(bufferHitEnergy > currentEnergy) {
-    				isCluster = false;
-    				break;
-    			}
-    			
-    			// If the buffer hit is smaller, then add its energy
-    			// to the cluster total energy.
-    			else {
-    				clusterEnergy += bufferHitEnergy;
-    				if(bufferHit != currentHit) { clusterComponentHits.add(bufferHit); }
-    			}
-    			
-    			// We must also make sure that the original hit is
-    			// larger than all of the neighboring hits at this
-    			// point in the buffer as well.
-    			for(Long neighborID : neighbors) {
-    				// Get the neighbor hit energy if it exists.
-        			double neighborHitEnergy = 0.0;
-        			CalorimeterHit neighborHit = bufferHits.get(neighborID);
-        			if(neighborHit != null) { neighborHitEnergy = neighborHit.getRawEnergy(); }
-        			
-        			// Check to see if the neighbor hit at this point
-        			// in the buffer is larger than then original hit.
-        			// If it is, we may stop the comparison because this
-        			// is not a cluster.
-        			if(neighborHitEnergy > currentEnergy) {
-        				isCluster = false;
-        				break;
-        			}
-        			
-        			// If the buffer neighbor hit is smaller, then
-        			// add its energy to the cluster total energy.
-        			else {
-        				clusterEnergy += neighborHitEnergy;
-        				clusterComponentHits.add(neighborHit);
-        			}
-    			}
-    			
-    			// If we exit from the neighbor loop and isCluster is
-    			// false, then one of the neighboring crystals had a
-    			// larger energy and we may break from this iteration.
-    			if(!isCluster) { break; }
+                // We must also make sure that the original hit is
+                // larger than all of the neighboring hits at this
+                // point in the buffer as well.
+                for (Long neighborID : neighbors) {
+                    // Get the neighbor hit energy if it exists.
+                    CalorimeterHit neighborHit = bufferHits.get(neighborID);
+                    if (neighborHit != null) {
+                        double neighborHitEnergy = neighborHit.getRawEnergy();
+
+                        // Check to see if the neighbor hit at this point
+                        // in the buffer is larger than then original hit.
+                        // If it is, we may stop the comparison because this
+                        // is not a cluster.
+                        if (neighborHitEnergy > currentEnergy) {
+                            continue seedLoop;
+                        } // If the buffer neighbor hit is smaller, then
+                        // add its energy to the cluster total energy.
+                        else if (neighborHitEnergy > addEnergyThreshold) {
+                            cluster.addHit(neighborHit);
+                        }
+                    }
+                }
     		}
     		
-    		// If the potential cluster center is still valid, check
+    		// If the potential cluster center is still valid, check
     		// that its cluster energy is above the minimum threshold.
-    		if(isCluster && clusterEnergy >= clusterEnergyThreshold) {
-    			// Generate a new cluster from this information.
-                CalorimeterHit seedHit = new HPSCalorimeterHit(0.0, currentHit.getTime(), currentID, currentHit.getType());
-                seedHit.setMetaData(currentHit.getMetaData());
-                HPSEcalCluster cluster = new HPSEcalCluster(seedHit);
-                
-                // Add all of the neighbors to the cluster.
-                for(CalorimeterHit neighbor : clusterComponentHits) { cluster.addHit(neighbor); }
-                
+    		if(cluster.getEnergy() >= clusterEnergyThreshold) {
                 // Add the cluster to the list of clusters.
                 clusters.add(cluster);
     		}
-    		
     	}
     	
     	// Return the generated list of clusters.
@@ -338,51 +246,33 @@
      * @param event - The event to process.
      */
     public void process(EventHeader event) {
-    	// Get the list calorimeter hits from the event.
-    	List<CalorimeterHit> hitList = event.get(CalorimeterHit.class, hitCollectionName);
-    	
-    	// Store each hit in a set by its cell ID so that it may be
-    	// easily acquired later.
-    	HashMap<Long, CalorimeterHit> hitMap = new HashMap<Long, CalorimeterHit>(hitList.size());
-    	for(CalorimeterHit hit : hitList) { hitMap.put(hit.getCellID(), hit); }
-    	
-    	// Remove the last event from the hit buffer and the new one.
-    	hitBuffer.removeLast();
-    	hitBuffer.addFirst(hitMap);
-    	eventBuffer.removeLast();
-    	eventBuffer.addFirst(event);
-    	
-    	// Process the current event.
-    	processEvent();
+        // Only run the clusterer if this event has the calorimeter hit collection. 
+        // This ensures this driver makes clusters in sync with the FADC readout cycle.
+        if (event.hasCollection(CalorimeterHit.class, hitCollectionName)) {
+            // Get the list of calorimeter hits from the event.
+            List<CalorimeterHit> hitList = event.get(CalorimeterHit.class, hitCollectionName);
+
+            // Store each hit in a set by its cell ID so that it may be
+            // easily acquired later.
+            HashMap<Long, CalorimeterHit> hitMap = new HashMap<Long, CalorimeterHit>();
+            for (CalorimeterHit hit : hitList) {
+                hitMap.put(hit.getCellID(), hit);
+            }
+
+            // Remove the last event from the hit buffer and add the new one.
+            hitBuffer.removeLast();
+            hitBuffer.addFirst(hitMap);
+
+            // Run the clustering algorithm on the buffer.
+            List<HPSEcalCluster> clusterList = getClusters();
+
+            // Store the cluster list in the LCIO collection.
+            int flag = 1 << LCIOConstants.CLBIT_HITS;
+            event.put(clusterCollectionName, clusterList, HPSEcalCluster.class, flag);
+        }
     }
     
     /**
-     * <b>processEvent</b><br/><br/>
-     * <code>private void <b>processEvent</b>()</code><br/><br/>
-     * Handles running the clustering algorithm and placing the results
-     * in the appropriate event header. Note that this is separate from
-     * <code>process</code> so that it can be called from <code>endOfData
-     * </code> as well.
-     */
-    private void processEvent() {
-    	// Get the current event.
-    	EventHeader event = eventBuffer.get(clusterWindow);
-    	
-    	// If the current event is null, then it is a blank event we
-    	// have inserted to simulate either past events at the start
-    	// of a run, or future events at the end of one. It requires
-    	// no further action.
-    	if(event == null) { return; }
-    	
-    	// Run the clustering algorithm on the buffer.
-    	List<HPSEcalCluster> clusterList = getClusters();
-    	
-    	// Store the cluster list in the LCIO collection.
-    	int flag = 1 << LCIOConstants.CLBIT_HITS;
-    	event.put(clusterCollectionName, clusterList, HPSEcalCluster.class, flag);
-    }
-    
-    /**
      * <b>setHitCollectionName</b><br/><br/>
      * <code>public void <b>setHitCollectionName</b>(String hitCollectionName)</code><br/><br/>
      * Sets the name of the LCIO collection containing the calorimeter
@@ -447,10 +337,8 @@
     	// The cluster window of must always be at least zero.
     	if(clusterWindow < 0) { this.clusterWindow = 0; }
     	
-    	// If the cluster window is non-zero, then store it. Note that
-    	// we double the size of the window because events are 2 ns,
-    	// while clock cycles are 4 ns.
-    	else { this.clusterWindow = 2 * clusterWindow; }
+    	// If the cluster window is non-zero, then store it.
+    	else { this.clusterWindow = clusterWindow; }
     }
     
     /**
@@ -471,6 +359,24 @@
     }
     
     /**
+     * <b>setAddEnergyThreshold</b><br/><br/>
+     * <code>public void <b>setAddEnergyThreshold</b>(double addEnergyThreshold)</code><br/><br/>
+     * Sets the minimum energy threshold below which a hit will not be added to
+     * a cluster.
+     *
+     * @param addEnergyThreshold - The minimum amount of energy for a cluster
+     * hit.
+     */
+    public void setAddEnergyThreshold(double addEnergyThreshold) {
+    	// A negative energy threshold is non-physical. All thresholds
+    	// be at least zero.
+    	if(addEnergyThreshold < 0.0) { this.addEnergyThreshold = 0.0; }
+    	
+    	// If the energy threshold is valid, then use it.
+    	else { this.addEnergyThreshold = addEnergyThreshold; }
+    }    
+    
+    /**
      * <b>startOfData</b><br/><br/>
      * <code>public void <b>startOfData</b>()</code><br/><br/>
      * Initializes the clusterer. This ensures that the collection name
@@ -492,7 +398,6 @@
         
         // Initiate the hit buffer.
         hitBuffer = new LinkedList<Map<Long, CalorimeterHit>>();
-        eventBuffer = new LinkedList<EventHeader>();
         
         // Populate the event buffer with (2 * clusterWindow + 1)
         // empty events. These empty events represent the fact that
@@ -501,7 +406,6 @@
         int bufferSize = (2 * clusterWindow) + 1;
         for(int i = 0; i < bufferSize; i++) {
         	hitBuffer.add(new HashMap<Long, CalorimeterHit>(0));
-        	eventBuffer.add(null);
         }
     }
 }
SVNspam 0.1