Author: [log in to unmask]
Date: Wed Dec 17 10:26:49 2014
New Revision: 1785
Log:
Updated GTPOnlineClusterer to its complete form. All tests suggest that clustering is now working correctly.
Modified:
java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/GTPOnlineClusterer.java
Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/GTPOnlineClusterer.java
=============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/GTPOnlineClusterer.java (original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/GTPOnlineClusterer.java Wed Dec 17 10:26:49 2014
@@ -7,6 +7,7 @@
import org.lcsim.event.CalorimeterHit;
import org.lcsim.event.EventHeader;
+import org.lcsim.lcio.LCIOConstants;
import org.lcsim.util.Driver;
/**
@@ -15,34 +16,58 @@
* online reconstruction/diagnostics or for general analysis of EVIO
* readout data.<br/>
* <br/>
- * <font color=red><b>WARNING:</b></font> This code is under construction
- * and does not currently function. It will crash the simulation with a
- * <code>RuntimeException</code> if any cluster is formed!
+ * The GTP algorithm searches the set of hits in a readout event and
+ * compares them to select those that are a maximum in their 3x3 window
+ * and across a period of time that can be set. Hits that are maxima
+ * are declared "cluster seeds" and a cluster is created from them.
+ * All hits within the clustering window of the seed time are then
+ * added to the cluster and it is written to the event stream.<br/>
+ * <br/>
+ * The GTP algorithm uses three time windows. THe verification window
+ * is the time around the seed hit in which it is required to have more
+ * energy than any other hits in the 3x3 spatial window surrounding it.
+ * This is always symmetric. The other two windows combined define the
+ * clustering window. The clustering window is composed of a window
+ * before and a window after the seed time. These may be defined using
+ * different values. The window after should be as long or longer than
+ * the window before to make physical sense. The verification window is
+ * then defined as the larger of the two constituents of the clustering
+ * window. This is required for clustering to be consistent.
*
* @author Kyle McCarty <[log in to unmask]>
*/
public class GTPOnlineClusterer extends Driver {
- private int eventNum = 0;
-
// The size of the temporal window in nanoseconds. By default,
// this is 1 clock-cycle before and 3 clock-cycles after.
private double timeBefore = 4;
private double timeAfter = 12;
+ private double timeWindow = 12;
+
+ // Cluster formation energy thresholds. Currently, the hardware
+ // only supports a lower bound seed energy. Units are in GeV.
+ private double seedThreshold = 0.050;
// The LCIO collection name for hits. This defaults to the collection
// name used by the EVIO to LCIO converter.
private String hitCollectionName = "EcalCalHits";
-
+ private String clusterCollectionName = "EcalClusters";
+
+ // Internal variables.
+ private boolean verbose = false;
+
+ /**
+ * Reads in hits and processes them into clusters as per the GTP
+ * clustering algorithm implemented in the hardware.
+ * @param event - The object containing event data.
+ */
+ @Override
public void process(EventHeader event) {
- // Increment the event number.
- eventNum++;
-
// Check if the event has a collection of the appropriate type
// and name for readout hits.
boolean hasHits = event.hasCollection(CalorimeterHit.class, hitCollectionName);
- // DEBUG :: Indicate whether the event has hits.
- System.out.printf("Event %7d :: Has hits [%5b]%n", eventNum, hasHits);
+ // VERBOSE :: Indicate whether the event has hits.
+ if(verbose) { System.out.printf("Event %7d :: Has hits [%5b]%n", event.getEventNumber(), hasHits); }
if(event.hasCollection(CalorimeterHit.class, hitCollectionName)) {
// Get the hits.
@@ -56,14 +81,16 @@
}
});
- // DEBUG :: Print the hit information.
- for(CalorimeterHit hit : hitList) {
- int ix = hit.getIdentifierFieldValue("ix");
- int iy = hit.getIdentifierFieldValue("iy");
- double energy = hit.getCorrectedEnergy();
- double time = hit.getTime();
-
- System.out.printf("\tHit --> %.3f GeV at (%3d, %3d) and at t = %.2f%n", energy, ix, iy, time);
+ // VERBOSE :: Print the hit information.
+ if(verbose) {
+ for(CalorimeterHit hit : hitList) {
+ int ix = hit.getIdentifierFieldValue("ix");
+ int iy = hit.getIdentifierFieldValue("iy");
+ double energy = hit.getCorrectedEnergy();
+ double time = hit.getTime();
+
+ System.out.printf("\tHit --> %.3f GeV at (%3d, %3d) and at t = %.2f%n", energy, ix, iy, time);
+ }
}
// A seed hit is a hit that is the largest both within its
@@ -79,8 +106,16 @@
// Iterate over each hit and see if it qualifies as a seed hit.
seedLoop:
for(CalorimeterHit seed : hitList) {
+ // Check whether the potential seed passes the seed
+ // energy cut.
+ if(seed.getCorrectedEnergy() < seedThreshold) {
+ continue seedLoop;
+ }
+
// Create a cluster for the potential seed.
- HPSEcalCluster protoCluster = new HPSEcalCluster(seed.getCellID());
+ HPSEcalCluster protoCluster = new HPSEcalCluster();
+ protoCluster.setSeedHit(seed);
+ protoCluster.addHit(seed);
// Iterate over the other hits and if the are within
// the clustering spatiotemporal window, compare their
@@ -91,13 +126,17 @@
if(hit != seed) {
// Check if the hit is within the spatiotemporal
// clustering window.
- if(withinTimeWindow(seed, hit) && withinSpatialWindow(seed, hit)) {
+ if(withinTimeVerificationWindow(seed, hit) && withinSpatialWindow(seed, hit)) {
// Check if the hit invalidates the potential
// seed.
if (isValidSeed(seed, hit)) {
- // Add the hit to the seed's component
- // hits and continue checking.
- protoCluster.addHit(hit);
+ // Make sure that the hit is also within
+ // the hit add window; this may not be
+ // the same as the verification window
+ // if the asymmetric window is active.
+ if(withinTimeClusteringWindow(seed, hit)) {
+ protoCluster.addHit(hit);
+ }
}
// If it is not, then skip the rest of the
@@ -114,27 +153,35 @@
clusterList.add(protoCluster);
}
- // DEBUG :: Print out all the clusters in the event.
- for(HPSEcalCluster cluster : clusterList) {
- int ix = cluster.getSeedHit().getIdentifierFieldValue("ix");
- int iy = cluster.getSeedHit().getIdentifierFieldValue("iy");
- double energy = cluster.getEnergy();
- double time = cluster.getSeedHit().getTime();
-
- System.out.printf("\tCluster --> %.3f GeV at (%3d, %3d) and at t = %.2f%n", energy, ix, iy, time);
-
- for(CalorimeterHit hit : cluster.getCalorimeterHits()) {
- int hix = hit.getIdentifierFieldValue("ix");
- int hiy = hit.getIdentifierFieldValue("iy");
- double henergy = hit.getCorrectedEnergy();
- double htime = hit.getTime();
- System.out.printf("\t\tCompHit --> %.3f GeV at (%3d, %3d) and at t = %.2f%n", henergy, hix, hiy, htime);
- }
- }
- }
-
- // DEBUG :: Print a new line.
- System.out.println();
+ // VERBOSE :: Print out all the clusters in the event.
+ if(verbose) {
+ for(HPSEcalCluster cluster : clusterList) {
+ int ix = cluster.getSeedHit().getIdentifierFieldValue("ix");
+ int iy = cluster.getSeedHit().getIdentifierFieldValue("iy");
+ double energy = cluster.getEnergy();
+ double time = cluster.getSeedHit().getTime();
+
+ System.out.printf("\tCluster --> %.3f GeV at (%3d, %3d) and at t = %.2f%n", energy, ix, iy, time);
+
+ for(CalorimeterHit hit : cluster.getCalorimeterHits()) {
+ int hix = hit.getIdentifierFieldValue("ix");
+ int hiy = hit.getIdentifierFieldValue("iy");
+ double henergy = hit.getCorrectedEnergy();
+ double htime = hit.getTime();
+ System.out.printf("\t\tCompHit --> %.3f GeV at (%3d, %3d) and at t = %.2f%n", henergy, hix, hiy, htime);
+ }
+ }
+ }
+
+ // Write out the clusters, if any exist, to the event stream.
+ if(clusterList.size() != 0) {
+ int flag = 1 << LCIOConstants.CLBIT_HITS;
+ event.put(clusterCollectionName, clusterList, HPSEcalCluster.class, flag);
+ }
+ }
+
+ // VERBOSE :: Print a new line.
+ if(verbose) { System.out.println(); }
}
/**
@@ -230,14 +277,35 @@
/**
* Checks whether the hit <code>hit</code> is within the temporal
- * window of the hit <code>seed</code>.
+ * window of the hit <code>seed</code> for the purpose of seed
+ * verification.
* @param seed - The seed hit.
* @param hit - The comparison hit.
* @return Returns <code>true</code> if the comparison hit is within
* the temporal window of the seed hit and <code>false</code>
* otherwise.
*/
- private boolean withinTimeWindow(CalorimeterHit seed, CalorimeterHit hit) {
+ private boolean withinTimeVerificationWindow(CalorimeterHit seed, CalorimeterHit hit) {
+ // If the hit is within the hit time window, it is valid.
+ if(Math.abs(seed.getTime() - hit.getTime()) <= timeWindow) {
+ return true;
+ }
+
+ // Otherwise, they are not.
+ else { return false; }
+ }
+
+ /**
+ * Checks whether the hit <code>hit</code> is within the temporal
+ * window of the hit <code>seed</code> for the purpose of adding
+ * a hit to a cluster.
+ * @param seed - The seed hit.
+ * @param hit - The comparison hit.
+ * @return Returns <code>true</code> if the comparison hit is within
+ * the temporal window of the seed hit and <code>false</code>
+ * otherwise.
+ */
+ private boolean withinTimeClusteringWindow(CalorimeterHit seed, CalorimeterHit hit) {
// Get the hit time and seed time.
double hitTime = hit.getTime();
double seedTime = seed.getTime();
@@ -277,6 +345,23 @@
}
/**
+ * Sets the name of the output LCIO hit collection.
+ * @param clusterCollectionName - The collection name.
+ */
+ public void setClusterCollectionName(String clusterCollectionName) {
+ this.clusterCollectionName = clusterCollectionName;
+ }
+
+ /**
+ * Sets the minimum energy a hit must have before it will be
+ * considered for cluster formation.
+ * @param seedThreshold - The seed threshold in GeV.
+ */
+ public void setSeedLowThreshold(double seedThreshold) {
+ this.seedThreshold = seedThreshold;
+ }
+
+ /**
* Sets the number of clock-cycles to include in the clustering
* window before the seed hit. One clock-cycle is four nanoseconds.
* @param cyclesBefore - The length of the clustering window before
@@ -284,6 +369,7 @@
*/
public void setWindowBefore(int cyclesBefore) {
timeBefore = cyclesBefore * 4;
+ timeWindow = Math.max(timeBefore, timeAfter);
}
/**
@@ -294,5 +380,6 @@
*/
public void setWindowAfter(int cyclesAfter) {
timeAfter = cyclesAfter * 4;
+ timeWindow = Math.max(timeBefore, timeAfter);
}
}
|