Print

Print


Author: [log in to unmask]
Date: Thu Aug  6 17:19:42 2015
New Revision: 3348

Log:
Updated documentation for many ecal-recon drivers. Classes TDCData and HeadBankData require documentation still; I am not familiar enough with their function to provide it.

Modified:
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java
    java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java	Thu Aug  6 17:19:42 2015
@@ -1,24 +1,36 @@
 package org.hps.recon.ecal.cluster;
 
 /**
- * Class <code>GTPClusterDriver</code> instantiates an instance of
- * the clustering algorithm framework for the Monte Carlo version
- * of the GTP algorithm. This version assumes that events are equal
- * to 2 ns beam bunches. The class also allows the seed energy threshold
- * and cluster window to be set as well as whether or not the algorithm
- * should employ an asymmetric time window and write out verbose debug
- * text.
+ * Class <code>GTPClusterDriver</code> is an implementation of the
+ * <code>ClusterDriver</code> class that defines employs the readout
+ * variant of the GTP hardware clustering algorithm. Specifics on the
+ * behavior of this algorithm can be found in its documentation.<br/>
+ * <br/>
+ * <code>GTPClusterDriver</code> allows for all of the variable settings
+ * used by the GTP algorithm to be defined. It also can be set to
+ * "verbose" mode, where it will output detailed information on each
+ * event and the cluster forming process. This is disabled by default,
+ * but can be enabled for debugging purposes.<br/>
+ * <br/>
+ * <code>GTPClusterDriver</code> is designed to read from Monte Carlo
+ * data organized into 2-ns beam bunches. It can not be used for hardware
+ * readout data, or Monte Carlo formatted in this style. For this data,
+ * the <code>GTPOnlineClusterer</code> should be employed instead.
  * 
  * @author Kyle McCarty <[log in to unmask]>
  * @author Jeremy McCormick <[log in to unmask]>
  * @see GTPClusterer
  */
 public class GTPClusterDriver extends ClusterDriver {
-    // The GTP clustering algorithm.
+	/** An instance of the clustering algorithm object for producing
+	 * cluster objects. */
     private final GTPClusterer gtp;
     
     /**
-     * Instantiates a new <code>GTPClusterer</code>.
+     * Instantiates a new <code>GTPClusterer</code>, which will produce
+     * clusters using the GTP algorithm in the 2-ns beam bunch scheme.
+     * It will, by default, use a 50 MeV seed energy cut with +/- 2 a
+     * clock-cycle verification and inclusion window.
      */
     public GTPClusterDriver() {
         clusterer = ClustererFactory.create("GTPClusterer");
@@ -27,66 +39,77 @@
     }
     
     /**
-     * Sets whether hits should be added to a cluster from the entire
-     * cluster window or just the "future" hits, plus one clock-cycle
-     * of "past" hits as a safety buffer to account for time uncertainty.
-     * 
-     * @param limitClusterRange - <code>true</code> indicates that
-     * the asymmetric clustering window should be used and <code>
-     * false</code> that the symmetric window should be used.
+     * Sets whether the behavior of the hit inclusion window with respect
+     * to the hit verification window. If set to <code>false</code>,
+     * both windows will be identical in size. Otherwise, the inclusion
+     * window will be equal in size after the seed hit, but encompass
+     * only one clock-cycle before the seed hit. This should be replaced
+     * by the method <code>setAsymmetricWindow</code>.
+     * @param limitClusterRange - <code>true</code> indicates that the
+     * asymmetric window should be used and <code>false</code> that it
+     * should not.
      */
     @Deprecated
     public void setLimitClusterRange(boolean limitClusterRange) {
-        gtp.setLimitClusterRange(limitClusterRange);
+        gtp.setAsymmetricWindow(limitClusterRange);
     }
     
     /**
-     * Sets the number of clock-cycles (4 ns) before and after a hit
-     * in which the hit must be the maximum energy hit in its 3 x 3
-     * window in order to be considered a seed hit and form a cluster.
+     * Sets the size of the hit verification temporal window. Note
+     * that this defines the size of the window in one direction, so
+     * the full time window will be <code>(2 * clusterWindow) + 1</code>
+     * clock-cycles in length. (i.e., it will be a length of
+     * <code>clusterWindow</code> before the seed hit, a length of
+     * <code>clusterWindow</code> after the seed hit, plus the cycle
+     * that includes the seed hit.) Time length is in clock-cycles.
      * @param clusterWindow - The number of clock-cycles around the
-     * hit in one direction; i.e. a value of 1 indicates that the full
-     * window will include the current clock-cycle, plus one cycle both
-     * before and after the current cycle. This gives a total number
-     * of cycles equal to (2 * clusterWindow) + 1.
+     * hit in one direction.
      */
     public void setClusterWindow(int clusterWindow) {
         gtp.getCuts().setValue("clusterWindow", clusterWindow);
     }
     
     /**
-     * Sets the minimum energy needed for a seed hit to form a cluster.
-     * @param seedEnergyThreshold - The minimum seed energy in GeV.
+     * Sets the minimum seed energy needed for a hit to be considered
+     * for forming a cluster. This is the seed energy lower bound trigger
+     * cut and is in units of GeV.
+     * @param seedEnergyThreshold - The minimum cluster seed energy in
+     * GeV.
      */
     public void setSeedEnergyThreshold(double seedEnergyThreshold) {
         gtp.getCuts().setValue("seedEnergyThreshold", seedEnergyThreshold);
     }
     
     /**
-     * Sets whether the clustering algorithm should use an asymmetric
-     * clustering window. The asymmetric window will include hits in
-     * a cluster that are present within the full time window ahead of
-     * the seed hit, but only one clock-cycle behind it. This is to
-     * allow for variation in hit timing with respect to the seed due
-     * to jitter in the hardware.
+     * Sets whether the behavior of the hit inclusion window with respect
+     * to the hit verification window. If set to <code>false</code>,
+     * both windows will be identical in size. Otherwise, the inclusion
+     * window will be equal in size after the seed hit, but encompass
+     * only one clock-cycle before the seed hit.
      * @param asymmetricWindow - <code>true</code> indicates that the
      * asymmetric window should be used and <code>false</code> that it
      * should not.
      */
     public void setAsymmetricWindow(boolean asymmetricWindow) {
-        gtp.setLimitClusterRange(asymmetricWindow);
+        gtp.setAsymmetricWindow(asymmetricWindow);
     }
     
     /**
      * Sets whether the clustering algorithm should output diagnostic
      * text or not.
-     * @param verbose <code>true</code> indicates that the driver should
+     * @param verbose - <code>true</code> indicates that the driver should
      * output diagnostic text and <code>false</code> that it should not.
      */
     public void setVerbose(boolean verbose) {
         gtp.setVerbose(verbose);
     }
     
+    /**
+     * Defines whether the output of this clusterer should be persisted
+     * to LCIO or not. By default, this 
+     * @param state - <code>true</code> indicates that clusters will
+     * be persisted, and <code>false</code> that they will not.
+     */
     @Override
     public void setWriteClusterCollection(boolean state) {
     	// Set the flag as appropriate with the superclass.

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java	Thu Aug  6 17:19:42 2015
@@ -15,37 +15,70 @@
 import org.lcsim.event.base.BaseCluster;
 
 /**
- * Class <code>GTPCalorimeterClusterer</code> processes events and
- * converts hits into clusters, where appropriate. It uses the modified
- * 2014 clustering algorithm.<br/>
+ * Class <code>GTPClusterer</code> is an implementation of the abstract
+ * class <code>AbstractClusterer</code> that is responsible for producing
+ * clusters using the GTP algorithm employed by the hardware.<br/>
  * <br/>
- * 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 2) clock cycles. Hits that pass these checks are then required
- * to additional have a total cluster energy that exceeds another tunable
- * minimum threshold.<br/>
+ * The GTP algorithm produces clusters by finding hits representing
+ * local spatiotemporal energy maxima and forming a cluster from the
+ * hits within the aforementioned spatiotemporal window. A given hit
+ * is first checked to see if it exceeds some minimum energy threshold
+ * (referred to as the "seed energy threshold"). If this is the case,
+ * the algorithm looks at all hits that occurred in the same crystal as
+ * the comparison hit, or any crystal directly adjacent to it, within
+ * a programmable time window. If the hit exceeds all hits meeting these
+ * criteria in energy, the hit is considered the “seed hit” of a cluster.
+ * Then, all hits within the 3x3 spatial window which occur in the time
+ * window are added to a <code>Cluster</code> object.<br/>
  * <br/>
- * A hit is added to a cluster as a component if it has a non-zero energy
- * and within the aforementioned tunable time buffer used for clustering
- * and is either at the same location as the seed hit or is a neighbor
- * to the seed hit.
- * @author Kyle McCarty
- * @author Sho Uemura
+ * Note that the algorithm employs two distinct temporal windows. The
+ * first is the “verification” window. This is used to check that the
+ * potential seed hit is a local maximum in energy, and is required to
+ * be symmetric (i.e. as long before the seed time as after it) to ensure
+ * consistency. The second temporal window is the “inclusion” window,
+ * which determines which hits are included in the cluster. The inclusion
+ * window can be asymmetric, but can not exceed the verification window
+ * in length. As an example, one could choose a 12 ns verification window,
+ * meaning that the algorithm would 12 ns before and after the seed hit
+ * to check that it has the highest energy, but use a 4 ns/12 ns inclusion
+ * window, meaning that the algorithm would only include hits in 3x3
+ * spatial window up to 4 ns before and up to 12 ns after the seed hit
+ * in the cluster. Due to the way the hardware processes hits, the higher
+ * energy parts of a cluster always occur first in time, so it is not
+ * necessarily desirable to include hits significantly before the seed.
+ * It is however, necessary to verify a hit’s status as a maximum across
+ * the full time window to ensure consistency in cluster formation.
+ * <code>GTPClusterer</code> automatically defines the inclusion window
+ * in terms of the verification window.<br/>
+ * <br/>
+ * <code>GTPClusterer</code> requires as input a collection of
+ * <code>CalorimeterHit</code> objects representing the event hits. It
+ * will then produce a collection of <code>Cluster</code> objects
+ * representing the GTP algorithm output. It is designed to be run on
+ * Monte Carlo events where each event represents a 2 ns beam bunch.
+ * If the input data is formatted in the style of hardware readout, the
+ * sister class <code>GTPOnlineClusterer</code> should be used instead.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ * @author Sho Uemura <[log in to unmask]>
+ * @see Cluster
+ * @see CalorimeterHit
+ * @see AbstractClusterer
+ * @see GTPOnlineClusterer
  */
 public class GTPClusterer extends AbstractClusterer {
-	
     /**
      * The minimum energy required for a hit to be considered as a
      * cluster center. Hits with energy less than this value will be
-     * ignored.
+     * ignored. This is the seed energy lower bound cut.
      */
     private double seedEnergyThreshold;
     
     /**
      * 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.
+     * checking if a cluster is a local maximum in space-time. This
+     * is the hit verification temporal window.
      */
     private int clusterWindow;
     
@@ -58,7 +91,8 @@
     
     /**
      * Whether an asymmetric or symmetric window should be used for
-     * adding hits to a cluster.
+     * adding hits to a cluster. This defines the hit inclusion temporal
+     * window with respect to the verification window.
      */
     private boolean limitClusterRange = false;
     
@@ -75,213 +109,23 @@
     private boolean writeHitCollection = true;
     
     /**
-     * Instantiates the clusterer.
+     * Instantiates a new instance of a Monte Carlo GTP clustering
+     * algorithm. It will use the default seed energy threshold of
+     * 50 MeV and a default hit inclusion window of +/- 2 ns. By
+     * default the cluster inclusion and verification windows are
+     * identical.
      */
     GTPClusterer() {
-        super(new String[] { "seedEnergyThreshold", "clusterWindow" }, new double[] { 0.00, 2.});
-    }
-    
-    /**
-     * Sets the clustering algorithm parameters.
-     */
-    @Override
-    public void initialize() {
-        // Set cuts.
-        setSeedEnergyThreshold(getCuts().getValue("seedEnergyThreshold"));
-        setClusterWindow((int) getCuts().getValue("clusterWindow"));
-        
-        // Initiate the hit buffer.
-        hitBuffer = new LinkedList<Map<Long, CalorimeterHit>>();
-        
-        // Populate the event buffer with (2 * clusterWindow + 1)
-        // empty events. These empty events represent the fact that
-        // the first few events will not have any events in the past
-        // portion of the buffer.
-        int bufferSize = (2 * clusterWindow) + 1;
-        for (int i = 0; i < bufferSize; i++) {
-            hitBuffer.add(new HashMap<Long, CalorimeterHit>(0));
-        }
-    }
-        
-    /**
-     * Generates a list of clusters from the current hit buffer. The
-     * "present" event is taken to be the list of hits occurring at
-     * index <code>clusterWindow</code>, which is the middle of the
-     * buffer.
-     * @return Returns a <code>List</code> of <code>HPSEcalCluster
-     * </code> objects generated from the current event.
-     */
-    private List<Cluster> getClusters() {
-        // Generate a list for storing clusters.
-        List<Cluster> clusters = new ArrayList<Cluster>();
-        
-        // Get the list of hits at the current time in the event buffer.
-        Map<Long, CalorimeterHit> currentHits = hitBuffer.get(clusterWindow);
-        
-        // VERBOSE :: Print the cluster window.
-        if(verbose) {
-        	// Print the event header.
-	        System.out.printf("%n%nEvent:%n");
-	        
-	        // Calculate some constants.
-	        int window = (hitBuffer.size() - 1) / 2;
-	        int bufferNum = 0;
-	        
-	        // Print out all of the hits in the event buffer.
-	        for(Map<Long, CalorimeterHit> bufferMap : hitBuffer) {
-	            System.out.printf("Buffer %d:%n", hitBuffer.size() - bufferNum - window - 1);
-	            CalorimeterHit hit = null;
-	            
-	            for(Entry<Long, CalorimeterHit> entry : bufferMap.entrySet()) {
-	            	hit = entry.getValue();
-	            	System.out.printf("\t(%3d, %3d) --> %.4f (%.4f)%n", hit.getIdentifierFieldValue("ix"),
-	            			hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy());
-	            }
-	            
-	            bufferNum++;
-	        }
-	        
-	        // If there are not hits, indicate this.
-	        if(currentHits.isEmpty()) { System.out.println("\tNo hits this event!"); }
-        }
-        
-        // 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()) {
-            // Get the actual hit object.
-            CalorimeterHit currentHit = currentHits.get(currentID);
-            
-            // VERBOSE :: Print the current cluster.
-            if(verbose) {
-	            System.out.printf("Cluster Check:%n");
-	        	System.out.printf("\t(%3d, %3d) --> %.4f%n", currentHit.getIdentifierFieldValue("ix"),
-	        			currentHit.getIdentifierFieldValue("iy"), currentHit.getCorrectedEnergy());
-            }
-            
-            // Store the energy of the current hit.
-            double currentEnergy = currentHit.getCorrectedEnergy();
-            
-            // If the hit energy is lower than the minimum threshold,
-            // then we immediately reject this hit as a possible cluster.
-            if (currentEnergy < seedEnergyThreshold) {
-            	// VERBOSE :: Note the reason the potential seed was
-            	//            rejected.
-            	if(verbose) { System.out.printf("\tREJECT :: Does not exceed seed threshold %.4f.%n", seedEnergyThreshold); }
-            	
-            	// Skip to the next potential seed.
-                continue seedLoop;
-            }
-            
-            // Store the crystals that are part of this potential cluster, 
-            // starting with the cluster seed candidate.
-            BaseCluster cluster = createBasicCluster();            
-            cluster.addHit(currentHit);
-            cluster.setPosition(currentHit.getDetectorElement().getGeometry().getPosition().v());
-            cluster.setNeedsPropertyCalculation(false);
-            
-            // Get the set of neighbors for this hit.
-            Set<Long> neighbors = neighborMap.get(currentHit.getCellID());
-            
-            // Sort through each event stored in the buffer.
-            int bufferIndex = 0;
-            for (Map<Long, CalorimeterHit> bufferHits : hitBuffer) {
-                // Get the hit energy at the current hit's position in
-                // the buffer, if it exists. Ignore the current seed candidate.
-                CalorimeterHit bufferHit = bufferHits.get(currentID);
-                if (bufferHit != null && bufferHit != currentHit) {
-                    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) {
-                    	// VERBOSE :: Output the reason the potential
-                    	//            seed was rejected along with the
-                    	//            hit that caused it.
-                    	if(verbose) {
-	                    	System.out.printf("\tREJECT :: Buffer hit surpasses hit energy.");
-	                    	System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", bufferHit.getIdentifierFieldValue("ix"),
-	                    			bufferHit.getIdentifierFieldValue("iy"), bufferHit.getCorrectedEnergy(), bufferHit.getRawEnergy());
-                    	}
-                    	
-                    	// Skip to the next potential seed.
-                        continue seedLoop;
-                    }
-                    
-                    // If the buffer hit is smaller, then add its energy
-                    // to the cluster total energy.
-                    else {
-                        if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(bufferHit); }
-                        else if(!limitClusterRange) { cluster.addHit(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.
-                    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) {
-                        	// VERBOSE :: Output the reason the potential
-                        	//            seed was rejected along with the
-                        	//            hit that caused it.
-                        	if(verbose) {
-	                        	System.out.printf("\tREJECT :: Buffer hit surpasses hit energy.%n");
-	                        	System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", neighborHit.getIdentifierFieldValue("ix"),
-	                        			neighborHit.getIdentifierFieldValue("iy"), neighborHit.getCorrectedEnergy(), neighborHit.getRawEnergy());
-                        	}
-                        	
-                        	// Skip to the next potential seed.
-                            continue seedLoop;
-                        }
-                        
-                        // If the buffer neighbor hit is smaller, then
-                        // add its energy to the cluster total energy.
-                        else {
-                            if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(neighborHit); }
-                            else if(!limitClusterRange) { cluster.addHit(neighborHit); }
-                        }
-                    }
-                }
-                
-                // Increment the buffer index.
-                bufferIndex++;
-            }
-            
-            // Add the cluster to the list of clusters.
-            clusters.add(cluster);
-            
-            // VERBOSE :: Output the clusters generated from this event.
-            if(verbose) {
-	            System.out.printf("Cluster added.%n");
-	            System.out.printf("\t(%3d, %3d) --> %.4f GeV --> %d hits%n", cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"),
-	            		cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"), cluster.getEnergy(), cluster.getCalorimeterHits().size());
-	            for(CalorimeterHit hit : cluster.getCalorimeterHits()) {
-	            	System.out.printf("\t\tCLUSTER HIT :: (%3d, %3d) --> %.4f%n", hit.getIdentifierFieldValue("ix"),
-	            			hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy());
-	            }
-            }
-        }
-        
-        // Return the generated list of clusters.
-        return clusters;
-    }
-    
-    /**
-     * Places hits from the current event into the event hit buffer
-     * and processes the buffer to extract clusters. Clusters are then
-     * stored in the event object.
-     * @param event - The event to process.
+        super(new String[] { "seedEnergyThreshold", "clusterWindow" }, new double[] { 0.050, 2 });
+    }
+    
+    /**
+     * Processes the argument <code>CalorimeterHit</code> collection and
+     * forms a collection of <code>Cluster</code> objects according to
+     * the GTP clustering algorithm.
+     * @param event - The object containing event data.
+     * @param hitList - A list of <code>CalorimeterHit</code> objects
+     * from which clusters should be formed.
      */
     public List<Cluster> createClusters(EventHeader event, List<CalorimeterHit> hits) {
         // Store each hit in a set by its cell ID so that it may be
@@ -327,61 +171,93 @@
     }
     
     /**
+     * Indicates the type of cluster that is generated by this algorithm.
+     * @return Returns the type of cluster as a <code>ClusterType</code>
+     * object; specifically, returns <code>ClusterType.GTP</code>.
+     */
+    @Override
+    public ClusterType getClusterType() {
+        return ClusterType.GTP;
+    }
+    
+    /**
+     * Sets the clustering algorithm parameters.
+     */
+    @Override
+    public void initialize() {
+        // Set cuts.
+        setSeedEnergyThreshold(getCuts().getValue("seedEnergyThreshold"));
+        setClusterWindow((int) getCuts().getValue("clusterWindow"));
+        
+        // Initiate the hit buffer.
+        hitBuffer = new LinkedList<Map<Long, CalorimeterHit>>();
+        
+        // Populate the event buffer with (2 * clusterWindow + 1)
+        // empty events. These empty events represent the fact that
+        // the first few events will not have any events in the past
+        // portion of the buffer.
+        int bufferSize = (2 * clusterWindow) + 1;
+        for (int i = 0; i < bufferSize; i++) {
+            hitBuffer.add(new HashMap<Long, CalorimeterHit>(0));
+        }
+    }
+    
+    /**
      * Sets the number of clock cycles before and after a given cycle
      * that will be used when checking whether a given hit is a local
      * maximum in both time and space. Note that a value of <code>N</code>
      * indicates that <code>N</code> clock cycles before and
      * <code>N</code> clock cycles after will be considered. Thusly, a
-     * total of <code>2N + 1</code> clock cycles will be used.
+     * total of <code>2N + 1</code> clock cycles will be used. This
+     * defines the size of the hit verification window. The inclusion
+     * window is defined as a function of this, as discussed in the
+     * method <code>setLimitClusterRange</code>.
      * @param clusterWindow - The number of additional clock cycles to
      * include in the clustering checks. A negative value will be treated
      * as zero.
      */
     void setClusterWindow(int clusterWindow) {
         // The cluster window of must always be at least zero.
-        if (clusterWindow < 0) {
-            this.clusterWindow = 0;
-        }
+        if (clusterWindow < 0) { this.clusterWindow = 0; }
         
         // If the cluster window is non-zero, then store it.
-        else {
-            this.clusterWindow = clusterWindow;
-        }
-    }
-    
-    /**
-     * Sets whether hits should be added to a cluster from the entire
-     * cluster window or just the "future" hits, plus one clock-cycle
-     * of "past" hits as a safety buffer to account for time uncertainty.
+        else { this.clusterWindow = clusterWindow; }
+    }
+    
+    /**
+     * Sets the behavior of the hit inclusion and verification temporal
+     * windows. If set to <code>true</code>, the hit inclusion window
+     * will be defined as one clock-cycle before the seed hit and the
+     * regular length of the verification window after the seed hit. If
+     * <code>false</code>, the inclusion window and the verification
+     * window are set to be identical.
      * @param limitClusterRange - <code>true</code> indicates that the
      * asymmetric clustering window should be used and <code>false</code>
      * that the symmetric window should be used.
      */
-    void setLimitClusterRange(boolean limitClusterRange) {
+    void setAsymmetricWindow(boolean limitClusterRange) {
         this.limitClusterRange = limitClusterRange;
     }
     
     /**
-     * Sets the minimum energy threshold below which hits will not be
-     * considered as cluster centers.
-     * @param seedEnergyThreshold - The minimum energy for a cluster center.
+     * Sets the minimum energy a hit must have before it will be
+     * considered for cluster formation.
+     * @param seedThreshold - The seed threshold in GeV.
      */
     void setSeedEnergyThreshold(double seedEnergyThreshold) {
         // A negative energy threshold is non-physical. All thresholds
         // be at least zero.
-        if (seedEnergyThreshold < 0.0) {
-            this.seedEnergyThreshold = 0.0;
-        } // If the energy threshold is valid, then use it.
-        else {
-            this.seedEnergyThreshold = seedEnergyThreshold;
-        }
-    }
-    
-    /**
-     * Sets whether diagnostic text should be written out or not.
-     * @param verbose - <code>true</code> indicates that diagnostic
-     * text will be written out and <code>false</code> that it will
-     * not.
+        if (seedEnergyThreshold < 0.0) { this.seedEnergyThreshold = 0.0; }
+        
+        // If the energy threshold is valid, then use it.
+        else { this.seedEnergyThreshold = seedEnergyThreshold; }
+    }
+    
+    /**
+     * Sets whether the clusterer should output diagnostic text or not.
+     * @param verbose - <code>true</code> indicates that the clusterer
+     * should output diagnostic text and <code>false</code> that it
+     * should not.
      */
     void setVerbose(boolean verbose) {
     	this.verbose = verbose;
@@ -398,13 +274,177 @@
     	writeHitCollection = state;
     }
     
-    /**
-     * Indicates the type of cluster that is generated by this algorithm.
-     * @return Returns the type of cluster as a <code>ClusterType</code>
-     * object, specifically, <code>ClusterType.GTP</code>.
-     */
-    @Override
-    public ClusterType getClusterType() {
-        return ClusterType.GTP;
-    }
+/**
+ * Generates a list of clusters from the current hit buffer. The
+ * "present" event is taken to be the list of hits occurring at
+ * index <code>clusterWindow</code>, which is the middle of the
+ * buffer.
+ * @return Returns a <code>List</code> of <code>HPSEcalCluster
+ * </code> objects generated from the current event.
+ */
+private List<Cluster> getClusters() {
+    // Generate a list for storing clusters.
+    List<Cluster> clusters = new ArrayList<Cluster>();
+    
+    // Get the list of hits at the current time in the event buffer.
+    Map<Long, CalorimeterHit> currentHits = hitBuffer.get(clusterWindow);
+    
+    // VERBOSE :: Print the cluster window.
+    if(verbose) {
+    	// Print the event header.
+        System.out.printf("%n%nEvent:%n");
+        
+        // Calculate some constants.
+        int window = (hitBuffer.size() - 1) / 2;
+        int bufferNum = 0;
+        
+        // Print out all of the hits in the event buffer.
+        for(Map<Long, CalorimeterHit> bufferMap : hitBuffer) {
+            System.out.printf("Buffer %d:%n", hitBuffer.size() - bufferNum - window - 1);
+            CalorimeterHit hit = null;
+            
+            for(Entry<Long, CalorimeterHit> entry : bufferMap.entrySet()) {
+            	hit = entry.getValue();
+            	System.out.printf("\t(%3d, %3d) --> %.4f (%.4f)%n", hit.getIdentifierFieldValue("ix"),
+            			hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy());
+            }
+            
+            bufferNum++;
+        }
+        
+        // If there are not hits, indicate this.
+        if(currentHits.isEmpty()) { System.out.println("\tNo hits this event!"); }
+    }
+    
+    // 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()) {
+        // Get the actual hit object.
+        CalorimeterHit currentHit = currentHits.get(currentID);
+        
+        // VERBOSE :: Print the current cluster.
+        if(verbose) {
+            System.out.printf("Cluster Check:%n");
+        	System.out.printf("\t(%3d, %3d) --> %.4f%n", currentHit.getIdentifierFieldValue("ix"),
+        			currentHit.getIdentifierFieldValue("iy"), currentHit.getCorrectedEnergy());
+        }
+        
+        // Store the energy of the current hit.
+        double currentEnergy = currentHit.getCorrectedEnergy();
+        
+        // If the hit energy is lower than the minimum threshold,
+        // then we immediately reject this hit as a possible cluster.
+        if (currentEnergy < seedEnergyThreshold) {
+        	// VERBOSE :: Note the reason the potential seed was
+        	//            rejected.
+        	if(verbose) { System.out.printf("\tREJECT :: Does not exceed seed threshold %.4f.%n", seedEnergyThreshold); }
+        	
+        	// Skip to the next potential seed.
+            continue seedLoop;
+        }
+        
+        // Store the crystals that are part of this potential cluster, 
+        // starting with the cluster seed candidate.
+        BaseCluster cluster = createBasicCluster();            
+        cluster.addHit(currentHit);
+        cluster.setPosition(currentHit.getDetectorElement().getGeometry().getPosition().v());
+        cluster.setNeedsPropertyCalculation(false);
+        
+        // Get the set of neighbors for this hit.
+        Set<Long> neighbors = neighborMap.get(currentHit.getCellID());
+        
+        // Sort through each event stored in the buffer.
+        int bufferIndex = 0;
+        for (Map<Long, CalorimeterHit> bufferHits : hitBuffer) {
+            // Get the hit energy at the current hit's position in
+            // the buffer, if it exists. Ignore the current seed candidate.
+            CalorimeterHit bufferHit = bufferHits.get(currentID);
+            if (bufferHit != null && bufferHit != currentHit) {
+                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) {
+                	// VERBOSE :: Output the reason the potential
+                	//            seed was rejected along with the
+                	//            hit that caused it.
+                	if(verbose) {
+                    	System.out.printf("\tREJECT :: Buffer hit surpasses hit energy.");
+                    	System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", bufferHit.getIdentifierFieldValue("ix"),
+                    			bufferHit.getIdentifierFieldValue("iy"), bufferHit.getCorrectedEnergy(), bufferHit.getRawEnergy());
+                	}
+                	
+                	// Skip to the next potential seed.
+                    continue seedLoop;
+                }
+                
+                // If the buffer hit is smaller, then add its energy
+                // to the cluster total energy.
+                else {
+                    if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(bufferHit); }
+                    else if(!limitClusterRange) { cluster.addHit(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.
+                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) {
+                    	// VERBOSE :: Output the reason the potential
+                    	//            seed was rejected along with the
+                    	//            hit that caused it.
+                    	if(verbose) {
+                        	System.out.printf("\tREJECT :: Buffer hit surpasses hit energy.%n");
+                        	System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", neighborHit.getIdentifierFieldValue("ix"),
+                        			neighborHit.getIdentifierFieldValue("iy"), neighborHit.getCorrectedEnergy(), neighborHit.getRawEnergy());
+                    	}
+                    	
+                    	// Skip to the next potential seed.
+                        continue seedLoop;
+                    }
+                    
+                    // If the buffer neighbor hit is smaller, then
+                    // add its energy to the cluster total energy.
+                    else {
+                        if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(neighborHit); }
+                        else if(!limitClusterRange) { cluster.addHit(neighborHit); }
+                    }
+                }
+            }
+            
+            // Increment the buffer index.
+            bufferIndex++;
+        }
+        
+        // Add the cluster to the list of clusters.
+        clusters.add(cluster);
+        
+        // VERBOSE :: Output the clusters generated from this event.
+        if(verbose) {
+            System.out.printf("Cluster added.%n");
+            System.out.printf("\t(%3d, %3d) --> %.4f GeV --> %d hits%n", cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"),
+            		cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"), cluster.getEnergy(), cluster.getCalorimeterHits().size());
+            for(CalorimeterHit hit : cluster.getCalorimeterHits()) {
+            	System.out.printf("\t\tCLUSTER HIT :: (%3d, %3d) --> %.4f%n", hit.getIdentifierFieldValue("ix"),
+            			hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy());
+            }
+        }
+    }
+    
+    // Return the generated list of clusters.
+    return clusters;
 }
+}

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java	Thu Aug  6 17:19:42 2015
@@ -8,18 +8,49 @@
 import org.lcsim.event.EventHeader;
 
 /**
- * Class <code>GTPOnlineClusterDriver</code> allows parameters for the
- * readout variant of the GTP algorithm to be set.
+ * Class <code>GTPOnlineClusterDriver</code> is an implementation of
+ * the <code>ClusterDriver</code> class that defines employs the readout
+ * variant of the GTP hardware clustering algorithm. Specifics on the
+ * behavior of this algorithm can be found in its documentation.<br/>
+ * <br/>
+ * <code>GTPOnlineClusterDriver</code> allows for all of the variable
+ * settings used by the GTP algorithm to be defined. It also can be
+ * set to "verbose" mode, where it will output detailed information on
+ * each event and the cluster forming process. This is disabled by
+ * default, but can be enabled for debugging purposes.<br/>
+ * <br/>
+ * Lastly, <code>GTPOnlineClusterDriver</code> can be set to draw its
+ * settings from the <code>ConfigurationManager</code> static class,
+ * which reads and stores settings extracted directly from EvIO data.
+ * This option is disabled by default, and can be activated with the
+ * method <code>setUseDAQConfig</code>. When enabled, no clusters will
+ * be generated until <code>ConfigurationManager</code> reads a config
+ * event. This requires that the driver <code>DAQConfigDriver</code>
+ * be included in the driver chain.<br/>
+ * <br/>
+ * <code>GTPOnlineClusterDriver</code> is designed for use on hardware
+ * readout data or Monte Carlo formatted in this style. It can not be
+ * used for 2-ns beam bunch formatted data. <code>GTPClusterDriver</code>
+ * should be used for this data instead.
  * 
  * @author Kyle McCarty <[log in to unmask]>
+ * @see GTPOnlineClusterer
+ * @see ConfigurationManager
+ * @see org.hps.recon.ecal.daqconfig.DAQConfigDriver
  */
 public class GTPOnlineClusterDriver extends ClusterDriver {
+	/** An instance of the clustering algorithm object for producing
+	 * cluster objects. */
     private final GTPOnlineClusterer gtp;
+    /** Indicates whether the <code>ConfigurationManager</code> object
+     * should be used for clustering settings or not. */
     private boolean useDAQConfig = false;
     
     /**
-     * Instantiates a new clustering algorithm using the readout
-     * variant of the GTP clustering algorithm.
+     * Initializes a clustering driver. This implements the readout
+     * variant of the hardware GTP algorithm, as defined in the class
+     * <code>GTPClusterer</code>.
+     * @see GTPOnlineClusterer
      */
     public GTPOnlineClusterDriver() {
     	// Instantiate the clusterer.
@@ -48,6 +79,15 @@
         });
     }
     
+    /**
+     * Processes an an <code>EventHeader</code> object to generate
+     * clusters. Events will not be processed if <code>UseDAQConfig</code>
+     * is <code>true</code> unless the <code>ConfigurationManager</code>
+     * static class has received a DAQ configuration from the event
+     * stream and is initialized. Driver <code>DAQConfigDriver</code>
+     * must be in the driver chain for this to occur.
+     * @see org.hps.recon.ecal.daqconfig.DAQConfigDriver
+     */
     @Override
     public void process(EventHeader event) {
     	// Only process an event if either the DAQ configuration is not
@@ -58,7 +98,8 @@
     }
     
     /**
-     * Outputs the clusterer settings.
+     * Outputs the clusterer settings at driver initialization, assuming
+     * <code>setVerbose</code> is set to <code>true</code>.
      */
     @Override
     public void startOfData() {
@@ -68,7 +109,8 @@
     
     /**
      * Sets the minimum seed energy needed for a hit to be considered
-     * for forming a cluster.
+     * for forming a cluster. This is the seed energy lower bound trigger
+     * cut and is in units of GeV.
      * @param seedEnergyThreshold - The minimum cluster seed energy in
      * GeV.
      */
@@ -80,6 +122,9 @@
     /**
      * Sets the number of clock-cycles to include in the clustering
      * window before the seed hit. One clock-cycle is four nanoseconds.
+     * This defines the first half of the temporal hit inclusion window.
+     * The temporal hit verification window is defined as
+     * <code>max(windowAfter, windowBefore) * 2) + 1</code>.
      * @param cyclesBefore - The length of the clustering window before
      * the seed hit in clock cycles.
      */
@@ -90,8 +135,12 @@
     /**
      * Sets the number of clock-cycles to include in the clustering
      * window after the seed hit. One clock-cycle is four nanoseconds.
+     * This defines the latter half of the temporal hit inclusion window.
+     * The temporal hit verification window is defined as
+     * <code>max(windowAfter, windowBefore) * 2) + 1</code>.
      * @param cyclesAfter - The length of the clustering window after
      * the seed hit in clock cycles.
+     * @see GTPOnlineClusterer
      */
     public void setWindowAfter(int cyclesAfter) {
         gtp.setWindowAfter(cyclesAfter);
@@ -109,9 +158,14 @@
     
     /**
      * Sets whether GTP settings should be drawn from the EvIO data
-     * DAQ configuration or read from the steering file.
+     * DAQ configuration or read from the steering file. If this is
+     * set to <code>true</code>, no clusters will be generated until
+     * the static class <code>ConfigurationManager</code> has received
+     * a DAQ settings event and initialized. If this class is not part
+     * of the driver chain, then no clusters will ever be created.
      * @param state - <code>true</code> means that DAQ configuration
      * will be used and <code>false</code> that it will not.
+     * @see org.hps.recon.ecal.daqconfig.DAQConfigDriver
      */
     public void setUseDAQConfig(boolean state) {
     	useDAQConfig = state;

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java	Thu Aug  6 17:19:42 2015
@@ -16,74 +16,115 @@
 
 /**
  * Class <code>GTPOnlineClusterer</code> is an implementation of the
- * GTP clustering algorithm for EVIO readout data for use in either
- * online reconstruction/diagnostics or for general analysis of EVIO
- * readout data.<br/>
+ * abstract class <code>AbstractClusterer</code> that is responsible
+ * for producing clusters using the GTP algorithm employed by the
+ * hardware.<br/>
  * <br/>
- * 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/>
+ * The GTP algorithm produces clusters by finding hits representing
+ * local spatiotemporal energy maxima and forming a cluster from the
+ * hits within the aforementioned spatiotemporal window. A given hit
+ * is first checked to see if it exceeds some minimum energy threshold
+ * (referred to as the "seed energy threshold"). If this is the case,
+ * the algorithm looks at all hits that occurred in the same crystal as
+ * the comparison hit, or any crystal directly adjacent to it, within
+ * a programmable time window. If the hit exceeds all hits meeting these
+ * criteria in energy, the hit is considered the “seed hit” of a cluster.
+ * Then, all hits within the 3x3 spatial window which occur in the time
+ * window are added to a <code>Cluster</code> object.<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.
+ * Note that the algorithm employs two distinct temporal windows. The
+ * first is the “verification” window. This is used to check that the
+ * potential seed hit is a local maximum in energy, and is required to
+ * be symmetric (i.e. as long before the seed time as after it) to ensure
+ * consistency. The second temporal window is the “inclusion” window,
+ * which determines which hits are included in the cluster. The inclusion
+ * window can be asymmetric, but can not exceed the verification window
+ * in length. As an example, one could choose a 12 ns verification window,
+ * meaning that the algorithm would 12 ns before and after the seed hit
+ * to check that it has the highest energy, but use a 4 ns/12 ns inclusion
+ * window, meaning that the algorithm would only include hits in 3x3
+ * spatial window up to 4 ns before and up to 12 ns after the seed hit
+ * in the cluster. Due to the way the hardware processes hits, the higher
+ * energy parts of a cluster always occur first in time, so it is not
+ * necessarily desirable to include hits significantly before the seed.
+ * It is however, necessary to verify a hit’s status as a maximum across
+ * the full time window to ensure consistency in cluster formation.
+ * <code>GTPOnlineClusterer</code> automatically selects the larger of
+ * the two inclusion window parts as the verification window length.<br/>
+ * <br/>
+ * <code>GTPOnlineClusterer</code> requires as input a collection of
+ * <code>CalorimeterHit</code> objects representing the event hits. It
+ * will then produce a collection of <code>Cluster</code> objects
+ * representing the GTP algorithm output. It also produces a series of
+ * distribution plots under the “GTP(O) Cluster Plots” header. It is
+ * designed to be run on readout events, either from the hardware or
+ * Monte Carlo that has been processed through the readout simulation.
+ * If the input data is formatted into constant-time beam bunches, the
+ * sister class <code>GTPClusterer</code> should be used instead.
  * 
  * @author Kyle McCarty <[log in to unmask]>
+ * @see Cluster
+ * @see CalorimeterHit
+ * @see AbstractClusterer
+ * @see GTPClusterer
  */
 public class GTPOnlineClusterer extends AbstractClusterer {
-    
-    // The size of the temporal window in nanoseconds. By default,
-    // this is 1 clock-cycle before and 3 clock-cycles after.
+	/**
+	 * The length of the temporal window for inclusing clusters that
+	 * occur before the seed hit.
+	 */
     private double timeBefore = 4;
+    
+    /**
+     * The length of the temporal window for including clusters that
+     * occur after the seed hit.
+     */
     private double timeAfter = 12;
+    
+    /**
+     * The length of the temporal window for verifying that a hit is
+     * a local maximum in energy. This length represents both halves
+     * of the verification window, so the full length would be defined
+     * by <code>timeWindow * 2 + 4</code> ns.
+     */
     private double timeWindow = 12;
-
-    // Cluster formation energy thresholds. Currently, the hardware
-    // only supports a lower bound seed energy. Units are in GeV.
+    
+    /**
+     * The minimum energy a hit must have to be considered for cluster
+     * seed formation. Units are in GeV.
+     */
     private double seedThreshold = 0.050;
     
-    // Internal variables.
+    /**
+     * Controls whether or not verbose diagnostic information is output.
+     */
     private boolean verbose = false;
     
     // Diagnostic plots.
     private AIDA aida = AIDA.defaultInstance();
-    IHistogram1D hitEnergy = aida.histogram1D("GTP(O) Cluster Plots :: Hit Energy Distribution", 256, -1.0, 2.2);
-    IHistogram1D clusterSeedEnergy = aida.histogram1D("GTP(O) Cluster Plots :: Cluster Seed Energy Distribution", 176, 0.0, 2.2);
-    IHistogram1D clusterHitCount = aida.histogram1D("GTP(O) Cluster Plots :: Cluster Hit Count Distribution", 9, 1, 10);
-    IHistogram1D clusterTotalEnergy = aida.histogram1D("GTP(O) Cluster Plots :: Cluster Total Energy Distribution", 176, 0.0, 2.2);
-    IHistogram2D hitDistribution = aida.histogram2D("GTP(O) Cluster Plots :: Hit Distribution", 46, -23, 23, 11, -5.5, 5.5);
-    IHistogram2D clusterDistribution = aida.histogram2D("GTP(O) Cluster Plots :: Cluster Seed Distribution", 46, -23, 23, 11, -5.5, 5.5);
-    IHistogram1D energyDistribution = aida.histogram1D("GTP(O) Cluster Plots :: Percent Negative Energy Distribution", 100, 0.0, 1.0);
+    private IHistogram1D hitEnergy = aida.histogram1D("GTP(O) Cluster Plot/Hit Energy Distribution", 256, -1.0, 2.2);
+    private IHistogram1D clusterSeedEnergy = aida.histogram1D("GTP(O) Cluster Plots/Cluster Seed Energy Distribution", 176, 0.0, 2.2);
+    private IHistogram1D clusterHitCount = aida.histogram1D("GTP(O) Cluster Plots/Cluster Hit Count Distribution", 9, 1, 10);
+    private IHistogram1D clusterTotalEnergy = aida.histogram1D("GTP(O) Cluster Plots/Cluster Total Energy Distribution", 176, 0.0, 2.2);
+    private IHistogram2D hitDistribution = aida.histogram2D("GTP(O) Cluster Plots/Hit Distribution", 46, -23, 23, 11, -5.5, 5.5);
+    private IHistogram2D clusterDistribution = aida.histogram2D("GTP(O) Cluster Plots/Cluster Seed Distribution", 46, -23, 23, 11, -5.5, 5.5);
+    private IHistogram1D energyDistribution = aida.histogram1D("GTP(O) Cluster Plots/Percent Negative Energy Distribution", 100, 0.0, 1.0);
     
     /**
      * Instantiates a new instance of a readout GTP clustering algorithm.
+     * This will use the default seed energy threshold of 50 MeV.
      */
     GTPOnlineClusterer() {
         super(new String[] { "seedThreshold" }, new double[] { 0.050 });
     }
     
     /**
-     * Gets any relevant cuts from the superclass and sets the local
-     * clusterer variables accordingly. 
-     */
-    public void initialize() {
-        seedThreshold = getCuts().getValue("seedThreshold");
-    }
-    
-    /**
-     * Reads in hits and processes them into clusters as per the GTP
-     * clustering algorithm implemented in the hardware.
+     * Processes the argument <code>CalorimeterHit</code> collection and
+     * forms a collection of <code>Cluster</code> objects according to
+     * the GTP clustering algorithm.
      * @param event - The object containing event data.
+     * @param hitList - A list of <code>CalorimeterHit</code> objects
+     * from which clusters should be formed.
      */
     @Override
     public List<Cluster> createClusters(EventHeader event, List<CalorimeterHit> hitList) {
@@ -95,6 +136,7 @@
     		System.out.println("=== GTP Readout Clusterer ============================================");
     		System.out.println("======================================================================");
     		
+    		// Sort the hits by x-index and then by y-index.
         	Collections.sort(hitList, new Comparator<CalorimeterHit>() {
 				@Override
 				public int compare(CalorimeterHit firstHit, CalorimeterHit secondHit) {
@@ -106,6 +148,8 @@
 					}
 				}
         	});
+        	
+        	// Print the hit collection.
         	System.out.println("Event Hit Collection:");
             for(CalorimeterHit hit : hitList) {
                 int ix = hit.getIdentifierFieldValue("ix");
@@ -155,7 +199,7 @@
                 protoCluster.setPosition(seed.getDetectorElement().getGeometry().getPosition().v());
                 protoCluster.setNeedsPropertyCalculation(false);
                 
-                // Iterate over the other hits and if the are within
+                // Iterate over the other hits and if they are within
                 // the clustering spatiotemporal window, compare their
                 // energies.
                 hitLoop:
@@ -217,16 +261,18 @@
         
         // VERBOSE :: Print out all the clusters in the event.
         if(verbose) {
+        	// Print the clusters.
         	System.out.println("Event Cluster Collection:");
             for(Cluster cluster : clusterList) {
+            	// Output basic cluster positional and energy data.
                 CalorimeterHit seedHit = cluster.getCalorimeterHits().get(0);
                 int ix = seedHit.getIdentifierFieldValue("ix");
                 int iy = seedHit.getIdentifierFieldValue("iy");
                 double energy = cluster.getEnergy();
                 double time = seedHit.getTime();
-                
                 System.out.printf("\tCluster --> %6.3f GeV at (%3d, %3d) and at t = %.2f%n", energy, ix, iy, time);
                 
+                // Output the cluster hit collection.
                 for(CalorimeterHit hit : cluster.getCalorimeterHits()) {
                     int hix = hit.getIdentifierFieldValue("ix");
                     int hiy = hit.getIdentifierFieldValue("iy");
@@ -241,16 +287,125 @@
         // VERBOSE :: Print a new line.
         if(verbose) { System.out.println(); }
         
+        // Return the list of clusters.
         return clusterList;
     }
     
     /**
-     * Checks whether the hit <code>hit</code> keeps the hit <code>seed
-     * </code> from meeting the criteria for being a seed hit. Note that
-     * this does not check to see if the two hits are within the valid
-     * spatiotemporal window of one another.
+     * Gets the type of cluster produced by this clusterer.
+     * @return Returns the cluster type as a <code>ClusterType</code>
+     * enumerable.
+     */
+    @Override
+    public ClusterType getClusterType() {
+        return ClusterType.GTP_ONLINE;
+    }
+    
+    /**
+     * Gets the seed energy lower bound threshold in units of GeV.
+     * @return Returns the threshold as a <code>double</code>.
+     */
+    public double getSeedLowThreshold() { return seedThreshold; }
+    
+    /**
+     * Gets the number of nanoseconds before the seed hit time that
+     * the clusterer will look to include hits when a cluster is formed.
+     * @return Returns the time window as a <code>double</code>.
+     */
+    public double getWindowBefore() { return timeBefore; }
+    
+    /**
+     * Gets the number of nanoseconds after the seed hit time that
+     * the clusterer will look to include hits when a cluster is formed.
+     * @return Returns the time window as a <code>double</code>.
+     */
+    public double getWindowAfter() { return timeAfter; }
+    
+    /**
+     * Sets up the clusterer parameters so that it is ready to be used.
+     * This should be run before the cluster formation.
+     */
+    @Override
+    public void initialize() {
+        seedThreshold = getCuts().getValue("seedThreshold");
+    }
+    
+    /**
+     * Returns whether the clusterer will output verbose diagnostic
+     * information.
+     * @return Returns <code>true</code> if the clusterer will output
+     * diagnostic information and <code>false</code> otherwise.
+     */
+    boolean isVerbose() { return verbose; }
+    
+    /**
+     * Sets the minimum energy a hit must have before it will be
+     * considered for cluster formation.
+     * @param seedThreshold - The seed threshold in GeV.
+     */
+    void setSeedLowThreshold(double seedThreshold) {
+        this.seedThreshold = seedThreshold;
+    }
+    
+    /**
+     * Sets whether the clusterer should output diagnostic text or not.
+     * @param verbose - <code>true</code> indicates that the clusterer
+     * should output diagnostic text and <code>false</code> that it
+     * should not.
+     */
+    void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+    
+    /**
+     * Sets the number of clock-cycles to include in the clustering
+     * window before the seed hit. One clock-cycle is four nanoseconds.
+     * Note that the larger of this time and the time defined in method
+     * <code>setWindowAfter</code> will be the verification window size.
+     * @param cyclesBefore - The length of the clustering window before
+     * the seed hit in clock cycles.
+     */
+    void setWindowBefore(int cyclesBefore) {
+    	// The cluster window can not be negative.
+    	if(cyclesBefore < 0) { cyclesBefore = 0; }
+    	
+    	// Convert the window to nanoseconds and set the two time
+    	// windows appropriately.
+        timeBefore = cyclesBefore * 4;
+        timeWindow = Math.max(timeBefore, timeAfter);
+    }
+    
+    /**
+     * Sets the number of clock-cycles to include in the clustering
+     * window after the seed hit. One clock-cycle is four nanoseconds.
+     * Note that the larger of this time and the time defined in method
+     * <code>setWindowBefore</code> will be the verification window size.
+     * @param cyclesAfter - The length of the clustering window after
+     * the seed hit in clock cycles.
+     */
+    void setWindowAfter(int cyclesAfter) {
+    	// The cluster window can not be negative.
+    	if(cyclesAfter < 0) { cyclesAfter = 0; }
+    	
+    	// Convert the window to nanoseconds and set the two time
+    	// windows appropriately.
+        timeAfter = cyclesAfter * 4;
+        timeWindow = Math.max(timeBefore, timeAfter);
+    }
+    
+    /**
+     * Compares the argument <code>CalorimeterHit</code> <code>hit</code>
+     * against the <code>CalorimeterHit</code> <code>seed</code> to see
+     * if <code>seed</code> meets the criteria for a seed hit given the
+     * presence of <code>hit</code>, which is assumed to be located in
+     * the appropriate spatiotemporal window.<br/>
+     * <br/>
+     * Note that it is the responsibility of the calling method to
+     * ascertain whether the two <code>CalorimeterHit</code> objects
+     * are actually within the proper spatial and temporal windows of
+     * one another.
      * @param seed - The potential seed hit.
-     * @param hit - The hit to compare with the seed.
+     * @param hit - The hit with which to compare the seed.
      * @return Returns <code>true</code> if either the two hits are the
      * same hit or if the hit does not invalidate the potential seed.
      * Returns <code>false</code> otherwise.
@@ -303,10 +458,12 @@
     }
     
     /**
-     * Checks whether the hit <code>hit</code> falls within the spatial
-     * window of the hit <code>Seed</code>. This is defined as within
-     * 1 index of the seed's x-index and similarly for the seed's
-     * y-index. 
+     * Checks whether the <code>CalorimeterHit</code> <code>hit</code>
+     * is within the 3x3 spatial window of <code>CalorimeterHit</code>
+     * <code>seed</code>. This is defined as <code>seed</code> having
+     * an x-index within +/-1 of the x-index of <code>hit</code> and
+     * similarly for the y-index. Allowance is made for the fact that
+     * the x-indices go from -1 to 1 and skip zero.
      * @param seed - The seed hit.
      * @param hit - The comparison hit.
      * @return Returns <code>true</code> if either both hits are the
@@ -353,9 +510,9 @@
     }
     
     /**
-     * Checks whether the hit <code>hit</code> is within the temporal
-     * window of the hit <code>seed</code> for the purpose of seed
-     * verification.
+     * Checks whether <code>CalorimeterHit</code> <code>hit</code> is
+     * within the verification temporal window for potential seed hit
+     * <code>seed</code>.
      * @param seed - The seed hit.
      * @param hit - The comparison hit.
      * @return Returns <code>true</code> if the comparison hit is within
@@ -373,9 +530,9 @@
     }
     
     /**
-     * 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.
+     * Checks whether <code>CalorimeterHit</code> <code>hit</code> is
+     * within the inclusion temporal window for potential seed hit
+     * <code>seed</code>.
      * @param seed - The seed hit.
      * @param hit - The comparison hit.
      * @return Returns <code>true</code> if the comparison hit is within
@@ -397,87 +554,11 @@
             return (hitTime - seedTime) <= timeAfter;
         }
         
-        // If the times are the same, the are within the window.
+        // If the times are the same, they are within the window.
         if(hitTime == seedTime) { return true; }
         
         // Otherwise, one or both times is undefined and should not be
         // treated as within time.
         else { return false; }
     }
-    
-    /**
-     * Gets the seed energy lower bound threshold in units of GeV.
-     * @return Returns the seed energy lower bound threshold.
-     */
-    public double getSeedLowThreshold() { return seedThreshold; }
-    
-    /**
-     * Gets the number of nanoseconds before the seed hit time the
-     * clusterer will look to verify the seed hit.
-     * @return Returns the size of the time window before the seed
-     * hit time.
-     */
-    public double getWindowBefore() { return timeBefore; }
-    
-    /**
-     * Gets the number of nanoseconds after the seed hit time the
-     * clusterer will look to verify the seed hit.
-     * @return Returns the size of the time window after the seed
-     * hit time.
-     */
-    public double getWindowAfter() { return timeAfter; }
-    
-    /**
-     * Returns whether the clusterer will output verbose diagnostic
-     * information.
-     * @return Returns <code>true</code> if the clusterer will output
-     * diagnostic information and <code>false</code> otherwise.
-     */
-    public boolean isVerbose() { return verbose; }
-    
-    /**
-     * 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
-     * the seed hit in clock cycles.
-     */
-    public void setWindowBefore(int cyclesBefore) {
-        timeBefore = cyclesBefore * 4;
-        timeWindow = Math.max(timeBefore, timeAfter);
-    }
-    
-    /**
-     * Sets the number of clock-cycles to include in the clustering
-     * window after the seed hit. One clock-cycle is four nanoseconds.
-     * @param cyclesAfter - The length of the clustering window after
-     * the seed hit in clock cycles.
-     */
-    public void setWindowAfter(int cyclesAfter) {
-        timeAfter = cyclesAfter * 4;
-        timeWindow = Math.max(timeBefore, timeAfter);
-    }
-    
-    /**
-     * Sets whether the clusterer should output diagnostic text or not.
-     * @param verbose - <code>true</code> indicates that the clusterer
-     * should output diagnostic text and <code>false</code> that it
-     * should not.
-     */
-    public void setVerbose(boolean verbose) {
-        this.verbose = verbose;
-    }
-    
-    @Override
-    public ClusterType getClusterType() {
-        return ClusterType.GTP_ONLINE;
-    }
 }

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java	Thu Aug  6 17:19:42 2015
@@ -10,7 +10,7 @@
  * the DAQ configuration that can be parsed from EVIO files. It works
  * in conjunction with the <code>DAQConfigDriver</code>, which obtains
  * the configuration parser object when available and passes it to this
- * manager, and <code>TriggerConfig</code>, which parses the EVIO data.
+ * manager, and <code>EvioDAQParser</code>, which parses the EVIO data.
  * 
  * @author Kyle McCarty <[log in to unmask]>
  * @see DAQConfigDriver

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java	Thu Aug  6 17:19:42 2015
@@ -5,8 +5,25 @@
 import org.lcsim.event.EventHeader;
 import org.lcsim.util.Driver;
 
+/**
+ * Class <code>DAQConfigDriver</code> is responsible for checking events
+ * for DAQ configuration settings, and then passing them to the associated
+ * class <code>ConfigurationManager</code> so that they can be accessed
+ * by other classes.<br/>
+ * <br/>
+ * This driver must be included in the driver chain if any other drivers
+ * in the chain rely on <code>ConfigurationManager</code>, as it can
+ * not be initialized otherwise.
+ * 
+ * @author Kyle McCarty
+ * @see ConfigurationManager
+ */
 public class DAQConfigDriver extends Driver {
-    
+    /**
+     * Checks an event for the DAQ configuration banks and passes them
+     * to the <code>ConfigurationManager</code>.
+     * @param - The event to check.
+     */
     @Override
     public void process(EventHeader event) {
         // Check if a trigger configuration bank exists.
@@ -21,5 +38,4 @@
             ConfigurationManager.updateConfiguration(daqConfig);
         }
     }
-    
 }

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java	Thu Aug  6 17:19:42 2015
@@ -12,6 +12,18 @@
 import org.hps.conditions.ecal.EcalChannel;
 import org.hps.conditions.ecal.EcalConditions;
 
+/**
+ * Class <code>EvioDAQParser</code> takes DAQ configuration banks from
+ * EvIO data and extracts the configuration parameters from them. These
+ * are then stored within package-accessible variables within the class.
+ * <br/><br/>
+ * Note that this class should not be used directly to acquire DAQ
+ * configuration data. It is intended to be used internally by the EvIO
+ * parser and the class <code>ConfigurationManager</code>. The latter
+ * should be used for accessing this information for any other classes.
+ * 
+ * @author Nathan Baltzell <[log in to unmask]>
+ */
 public class EvioDAQParser {
     /*
      * Read/Parse/Save the DAQ trigger configuration settings.
@@ -22,135 +34,271 @@
      * 
      * GTP settings and Prescale factors will need to be added to this class when added to EVIO.
      * 
-     * TODO: Error in EVIO format for Crate 39 for 2014 data requires another JEVIO workaround (realized Feb 16).
+     * TODO: Error in EVIO format for Crate 39 for 2014 data requires another JEVIO workaround (realized Feb. 16).
      *       ** This was fixed in EVIO for data after run 4044.
      * 
      * TODO: Manually put in GTP settings based on run number for 2014 data.
      * TODO: Manually deal with change in format of SSP_HPS_SINGLES_NMIN (at 3312(?)).
      * 
-     * TODO: Restructure, clean up..
-     *  
-     *  @author <[log in to unmask]>
-     */
-    public int nBanks = 0;
+     * TODO: Restructure, clean up...
+     */
+	/** The EvIO bank identification tag for DAQ configuration banks. */
     public static final int BANK_TAG = 0xE10E;
     
-    // need to know these in order to interpret DAQ strings:
+    // Stores the hardware codes for each trigger type.
     private static final int[] singlesIOsrc = { 20, 21 };
     private static final int[] pairsIOsrc = { 22, 23 };
     
     // Dump everything read from the DAQ Configuration Bank, minimal interpretation:
-    Map<String,List<String>> configMap = new HashMap<String,List<String>>();
-    
-    // link ECAL FADC channel settings to EcalChannels:
-    Map<EcalChannel,Float> GAIN = new HashMap<EcalChannel,Float>();
-    Map<EcalChannel,Float> PEDESTAL = new HashMap<EcalChannel,Float>();
-    Map<EcalChannel,Integer> THRESHOLD = new HashMap<EcalChannel,Integer>();
-    
-    // private boolean debug = true;
+    private Map<String, List<String>> configMap = new HashMap<String, List<String>>();
+    
+    // Class parameters.
+    private int nBanks = 0;
     private boolean debug = false;
     
     // FADC Config:
+    /** The length of time after a pulse-crossing event that the pulse
+     * should be integrated. Uses units of clock-cycles. */
     int fadcNSA    = 0;
+    /** The length of time before a pulse-crossing event that the pulse
+     * should be integrated. Uses units of clock-cycles. */
     int fadcNSB    = 0;
+    /** The maximum number of pulses that will be extracted from a single
+     * channel within  a readout window. */
     int fadcNPEAK  = 0;
+    /** The pulse-processing mode used by the FADC. This should be 1,
+     * 3, or 7. */
     int fadcMODE   = 0;
+    /** The size of readout window in nanoseconds. */
     int fadcWIDTH  = 0;
+    /** The time-offset of the readout window in ns. */
     int fadcOFFSET = 0;
+    /** Map of <code>EcalChannel</code> to the gain for that channel.
+     * Uses units of ADC / MeV for the mapped value. */
+    Map<EcalChannel, Float> GAIN = new HashMap<EcalChannel, Float>();
+    /** Map of <code>EcalChannel</code> to the pedestal for that channel.
+     * Uses units of ADC for the mapped value. */
+    Map<EcalChannel, Float> PEDESTAL = new HashMap<EcalChannel, Float>();
+    /** Map of <code>EcalChannel</code> to the threshold for that channel.
+     * Uses units of ADC for the mapped value. */
+    Map<EcalChannel, Integer> THRESHOLD = new HashMap<EcalChannel, Integer>();
     
     // GTP Clustering Cut Values:
+    /** The seed energy lower bound cut used by the clusterer. Value is
+     * in units of MeV. */
     int gtpMinSeedEnergy  = 0;
+    /** The length of the clustering verification/inclusion window before
+     * the seed hit. Uses units of clock-cycles. */
     int gtpWindowBefore = 0;
+    /** The length of the clustering verification/inclusion window after
+     * the seed hit. Uses units of clock-cycles. */
     int gtpWindowAfter = 0;
     
     // Triggers Enabled:
+    /** Indicates whether the singles triggers are enabled or not. Uses
+     * the format <code>{ Singles0_Enabled, Singles1_Enabled }</code>. */
     boolean[] singlesEn = { false, false };
+    /** Indicates whether the pair triggers are enabled or not. Uses
+     * the format <code>{ Pair0_Enabled, Pair1_Enabled }</code>. */
     boolean[] pairsEn   = { false, false };
     
     // Singles Cuts Enabled:
+    /** Indicates whether the singles trigger cluster hit count cuts
+     * are enabled or not. Uses the format
+     * <code>{ Singles0_Cut_Enabled, Singles1_Cut_Enabled }</code>. */
     boolean[] singlesNhitsEn     = { false, false };
+    /** Indicates whether the singles trigger cluster total energy lower
+     * bound cuts are enabled or not. Uses the format
+     * <code>{ Singles0_Cut_Enabled, Singles1_Cut_Enabled }</code>. */
     boolean[] singlesEnergyMinEn = { false, false };
+    /** Indicates whether the singles trigger cluster total energy upper
+     * bound cuts are enabled or not. Uses the format
+     * <code>{ Singles0_Cut_Enabled, Singles1_Cut_Enabled }</code>. */
     boolean[] singlesEnergyMaxEn = { false, false };
     
     // Pairs Cuts Enabled:
+    /** Indicates whether the pair trigger pair energy sum cuts are
+     * enabled or not. Uses the format
+     * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */
     boolean[] pairsEnergySumMaxMinEn = { false, false };
+    /** Indicates whether the pair trigger pair energy difference cuts
+     * are enabled or not. Uses the format
+     * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */
     boolean[] pairsEnergyDiffEn      = { false, false };
+    /** Indicates whether the pair trigger pair coplanarity cuts are
+     * enabled or not. Uses the format
+     * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */
     boolean[] pairsCoplanarityEn     = { false, false };
+    /** Indicates whether the pair trigger pair energy slope cuts are
+     * enabled or not. Uses the format
+     * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */
     boolean[] pairsEnergyDistEn      = { false, false };
     
     // Singles Cut Values:
+    /** Specifies the value of the singles trigger cluster hit count
+     * cuts. Use the format, in units of hits,
+     * <code>{ Singles0_Cut_Value, Singles1_Cut_Value }</code>. */
     int[] singlesNhits     = { 0, 0 };
+    /** Specifies the value of the singles trigger cluster total energy
+     * lower bound cuts. Use the format, in units of MeV,
+     * <code>{ Singles0_Cut_Value, Singles1_Cut_Value }</code>. */
     int[] singlesEnergyMin = { 0, 0 };
+    /** Specifies the value of the singles trigger cluster total energy
+     * upper bound cuts. Use the format, in units of MeV,
+     * <code>{ Singles0_Cut_Value, Singles1_Cut_Value }</code>. */
     int[] singlesEnergyMax = { 0, 0 };
     
     // Pairs Cut Values:
+    /** Specifies the value of the pair trigger cluster hit count cuts.
+     * Use the format, in units of hits,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsNhitsMin       = { 0, 0 };
+    /** Specifies the value of the pair trigger cluster total energy
+     * lower bound cuts. Use the format, in units of MeV,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsEnergyMin      = { 0, 0 };
+    /** Specifies the value of the pair trigger cluster total energy
+     * upper bound cuts. Use the format, in units of MeV,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsEnergyMax      = { 0, 0 };
+    /** Specifies the value of the pair trigger pair energy sum upper
+     * bound cuts. Use the format, in units of MeV,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsEnergySumMin   = { 0, 0 };
+    /** Specifies the value of the pair trigger pair energy sum lower
+     * bound cuts. Use the format, in units of MeV,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsEnergySumMax   = { 0, 0 };
+    /** Specifies the value of the pair trigger pair energy difference
+     * cuts. Use the format, in units of MeV,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsEnergyDiffMax  = { 0, 0 };
+    /** Specifies the value of the pair trigger pair coplanarity cuts.
+     * Use the format, in units of degrees,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsCoplanarityMax = { 0, 0 };
+    /** Specifies the value of the pair trigger pair time coincidence
+     * cuts. Use the format, in units of nanoseconds,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsTimeDiffMax    = { 0, 0 };
+    /** Specifies the value of the pair trigger pair energy slope cuts.
+     * Use the format, in units of MeV,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     int[] pairsEnergyDistMin  = { 0, 0 };
     
     // Pairs Cut Parameters:
+    /** Specifies the value of the pair trigger pair energy slope cuts'
+     * parameter F. Use the format, in units of MeV / mm,
+     * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */
     float[] pairsEnergyDistSlope = { 0, 0 };
     
-    // Have to remember the previous slot line in order to interpret the data:
+    // Tracks the last FADC slot seen. This is needed for parsing FADC
+    // threshold, pedestal, and gain information.
     private int thisFadcSlot = 0;
     
     // Cache local set of EcalChannels:
     private EcalConditions ecalConditions = null;
     private List<EcalChannel> channels = new ArrayList<EcalChannel>();
     
+    /**
+     * Instantiates the <code>EvioDAQParser</code>.
+     */
     public EvioDAQParser() {
+    	// Create a map to map crystals to their database channel object.
         ecalConditions = DatabaseConditionsManager.getInstance().getEcalConditions();
         for (int ii = 0; ii < 442; ii++) {
-            channels.add(findChannel(ii+1));
+            channels.add(findChannel(ii + 1));
         } 
     }
     
-    public void parse(int crate, int runNumber, String[] dump) {
+    /**
+     * Parses a set of configuration tables to obtain DAQ configuration
+     * parameters.
+     * @param crate - The crate associated with the configuration tables.
+     * @param runNumber - The run number for the current data set.
+     * @param configurationTables - Tables containing DAQ configuration
+     * parameters.
+     */
+    public void parse(int crate, int runNumber, String[] configurationTables) {
+    	// Track the number of banks that have been parsed. If the
+    	// parameter values have not been populated after a certain
+    	// number of banks, there is missing information.
         nBanks++;
-        loadConfigMap(crate,dump); 
-        if (debug) printMap();
+        
+        // Create a map that maps an identifier for each configuration
+        // parameter (its parameter key) to any values associated
+        // with it (its parameter values).
+        loadConfigMap(crate, configurationTables);
+        
+        // If debugging text is enabled, print the map to the terminal.
+        if(debug) { printMap(); }
+        
+        // If this run is known to be missing configuration values,
+        // handle the missing values.
         fixConfigMap2014Run(runNumber);
+        
+        // Parse the previously generated configuration map and extract
+        // the DAQ configuration from it.
         parseConfigMap();
         
+        // If the expected number of banks have been parsed and debugging
+        // text is enabled, print out all of the parsed variables.
         if(nBanks > 2 && debug) { printVars(); }
     }
     
-    /*
-     * The first parsing routine.  Just dumps the config strings
-     * into a map whose keys are the first column in the config file.
-     * Also treats some special cases.
-     */
-    private void loadConfigMap(int crate, String[] dump) {
-        for(String dump1 : dump) {
-            for(String line : dump1.trim().split("\n")) {
+    /**
+     * Converts the textual configuration information into a map, where
+     * the first column value becomes the map entry key and the remainder
+     * becomes the map entry value.
+     * @param crate - The calorimeter crate associated with the textual
+     * configuration data.
+     * @param configTables - An array of textual configuration tables that
+     * contain the DAQ configuration parameters.
+     */
+    private void loadConfigMap(int crate, String[] configTables) {
+    	// Iterate over each configuration table.
+        for(String configTable : configTables) {
+        	// Split each table into rows and iterate over the rows.
+        	rowLoop:
+            for(String line : configTable.trim().split("\n")) {
+                // Split the first column from the row.
+                String[] cols = line.trim().split(" +", 2);
                 
-                String[] cols = line.trim().split(" +", 2);
-                if(cols.length < 2) continue;
+                // If there are fewer than two segments after the split,
+                // then this is not a valid parameter entry.
+                if(cols.length < 2) continue rowLoop;
                 
+                // The row name is the value of the first column. The
+                // rest are typically values.
                 String key = cols[0];
-                List<String> vals = new ArrayList<String>
-                    (Arrays.asList(cols[1].trim().split(" +")));
+                List<String> vals = new ArrayList<String>(Arrays.asList(cols[1].trim().split(" +")));
                 
+                // If no values are present, this is not a valid entry.
                 if (vals.size() < 1) {
-                    continue;
+                    continue rowLoop;
                 }
-               
-                // SPECIAL CASE:
-                // parse the 16+1 column slot configurations. 
+                
+                // SPECIAL CASE:: Key "FADC250"
+                // This entry marks parameter values for FADC channels,
+                // such as pedestals, gains, and thresholds. These are
+                // stored in separate lists from the other parameters.
                 if (key.startsWith("FADC250")) {
                     parseFADC(crate, key.trim(), vals);
                 }
                 
-                // SPECIAL CASE:
-                // figure out which triggers are enabled:
+                // SPECIAL CASE: Key "SSP_HPS_SET_IO_SRC"
+                // This entry indicates which triggers are enabled and
+                // needs to be parsed differently than normal.
                 else if(key.startsWith("SSP_HPS_SET_IO_SRC")) {
+                	// The first "parameter value" is a hardware code
+                	// that identifies the trigger. Obtain it.
                     int trig = Integer.valueOf(vals.get(1));
+                    
+                    // There are two trigger of each type, singles and
+                    // pairs. Compare the hardware code to the codes
+                    // for each of these triggers to determine which
+                    // it this parameter entry represents and then set
+                    // its value appropriately.
                     for (int ii = 0; ii < pairsIOsrc.length; ii++) {
                         if(trig == singlesIOsrc[ii]) {
                             singlesEn[ii] = true;
@@ -160,50 +308,60 @@
                         }
                     }
                 }
-               
-                // GENERAL CASE:
-                // Append trigger# onto key:
+                
+                // GENERAL CASE: Basic Parameter
+                // This indicates a regular parameter that does not
+                // require any special parsing.
                 if(vals.size() > 1 && key.startsWith("SSP")) {
+                	// List the parameter by "[ROW NAME]_[KEY]" and
+                	// remove the key so that only the values remain.
                     key += "_" + vals.remove(0);
                 }
-                // dump it into the map:
+                
+                // Add the parameter key and its values to the map.
                 configMap.put(key, vals);
             }
         }
     }
     
-    /*
-     * This function parses the config map for the cases where the
-     * config string has a simple format:
-     * TAG VALUE
-     * TAG TRIGGER VALUES
+    /**
+     * Parses the configuration parameter map entries and extracts the
+     * parameter values for those parameters which have the standard
+     * format of <code>[PARAMETER KEY] --> { [PARAMETER VALUES] }</code>.
      */
     public void parseConfigMap() {
-        fadcNSA    = Integer.valueOf(getConfig("FADC250_NSA", 0));
-        fadcNSB    = Integer.valueOf(getConfig("FADC250_NSB", 0));
-        fadcNPEAK  = Integer.valueOf(getConfig("FADC250_NPEAK", 0));
-        fadcMODE   = Integer.valueOf(getConfig("FADC250_MODE", 0));
-        fadcWIDTH  = Integer.valueOf(getConfig("FADC250_W_WIDTH", 0));
-        fadcOFFSET = Integer.valueOf(getConfig("FADC250_W_OFFSET", 0));
-        
-        gtpMinSeedEnergy = Integer.valueOf(getConfig("GTP_CLUSTER_PULSE_THRESHOLD", 0));
-        gtpWindowBefore  = Integer.valueOf(getConfig("GTP_CLUSTER_PULSE_COIN", 0));
-        gtpWindowAfter   = Integer.valueOf(getConfig("GTP_CLUSTER_PULSE_COIN", 1));
-        
+    	// Parse simple FADC data.
+        fadcNSA    = Integer.valueOf(getConfigParameter("FADC250_NSA",      0));
+        fadcNSB    = Integer.valueOf(getConfigParameter("FADC250_NSB",      0));
+        fadcNPEAK  = Integer.valueOf(getConfigParameter("FADC250_NPEAK",    0));
+        fadcMODE   = Integer.valueOf(getConfigParameter("FADC250_MODE",     0));
+        fadcWIDTH  = Integer.valueOf(getConfigParameter("FADC250_W_WIDTH",  0));
+        fadcOFFSET = Integer.valueOf(getConfigParameter("FADC250_W_OFFSET", 0));
+        
+        // Parse GTP data.
+        gtpMinSeedEnergy = Integer.valueOf(getConfigParameter("GTP_CLUSTER_PULSE_THRESHOLD", 0));
+        gtpWindowBefore  = Integer.valueOf(getConfigParameter("GTP_CLUSTER_PULSE_COIN",      0));
+        gtpWindowAfter   = Integer.valueOf(getConfigParameter("GTP_CLUSTER_PULSE_COIN",      1));
+        
+        // Parse trigger data.
         for(int ii = 0; ii < 2; ii++) {
+        	// Check singles trigger cuts enabled status.
             singlesNhitsEn[ii]         = getBoolConfigSSP(ii,  "SINGLES_NMIN",          1);
             singlesEnergyMinEn[ii]     = getBoolConfigSSP(ii,  "SINGLES_EMIN",          1);
             singlesEnergyMaxEn[ii]     = getBoolConfigSSP(ii,  "SINGLES_EMAX",          1);
             
+        	// Check pair trigger cuts enabled status.
             pairsEnergySumMaxMinEn[ii] = getBoolConfigSSP(ii,  "PAIRS_SUMMAX_MIN",      2);
             pairsEnergyDiffEn[ii]      = getBoolConfigSSP(ii,  "PAIRS_DIFFMAX",         1);
             pairsCoplanarityEn[ii]     = getBoolConfigSSP(ii,  "PAIRS_COPLANARITY",     1);
             pairsEnergyDistEn[ii]      = getBoolConfigSSP(ii,  "PAIRS_ENERGYDIST",      2);
             
+            // Get the singles trigger cuts.
             singlesNhits[ii]           = getIntConfigSSP(ii,   "SINGLES_NMIN",          0);
             singlesEnergyMin[ii]       = getIntConfigSSP(ii,   "SINGLES_EMIN",          0);
             singlesEnergyMax[ii]       = getIntConfigSSP(ii,   "SINGLES_EMAX",          0);
             
+            // Get the pair trigger cuts.
             pairsNhitsMin[ii]          = getIntConfigSSP(ii,   "PAIRS_NMIN",            0);
             pairsEnergyMin[ii]         = getIntConfigSSP(ii,   "PAIRS_EMIN",            0);
             pairsEnergyMax[ii]         = getIntConfigSSP(ii,   "PAIRS_EMAX",            0);
@@ -217,20 +375,18 @@
         }
     }
     
-    
-    
-    /*
-     * UNFINISHED.
-     * This is a fixer-upper for before we had the full config in EVIO
-     * or when there was a bug in it.
+    /**
+     * Method corrects parameter data for runs that either did not
+     * correctly record the full configuration data or were bugged.
+     * It populates missing fields with a zero value entry.
+     * @param runNumber - The run number for the current run. This is
+     * used to determine if the run is a "bugged" run.
      */
     private void fixConfigMap2014Run(int runNumber) {
+    	// If this is a good run, noting should be done. Return.
         if(runNumber > 3470 || runNumber < 3100) { return; }
-        // TODO: port datacat/python/engrun/engrun_metadata.py
-        // 1. SET GTP SETTINGS MANUALLY BASED ON RUN NUMBER
-        // 2. FIX SINGLES_NMIN prior to 3312
-        for (String key : configMap.keySet()) {
-        }
+        
+        // Populate missing GTP entries.
         List<String> tmp = new ArrayList<String>();
         tmp.add("0");
         tmp.add("0");
@@ -238,41 +394,90 @@
         tmp.add("0");
         configMap.put("GTP_CLUSTER_THRESH" ,tmp);
         configMap.put("GTP_TIMEDIFF", tmp);
-    }
-    
-    /*
-     * These treat the FADC config lines with 16+1 columns.
-     * Must keep track of most recent FADC250_SLOT tag, since it's
-     * not on the line with the data. 
+        
+        // TODO: Port datacat/python/engrun/engrun_metadata.py
+        // 1. SET GTP SETTINGS MANUALLY BASED ON RUN NUMBER
+        // 2. FIX SINGLES_NMIN prior to 3312
+    }
+    
+    /**
+     * Parses FADC configuration parameter entries. These all have 17
+     * lines, the first of which is the parameter key and the subsequent
+     * being parameter values corresponding to the 16 FADC channels for
+     * the indicated FADC slot. These entries contain thresholds, gains,
+     * and pedestals.
+     * @param crate - The crate associated with this parameter entry.
+     * @param key - The parameter key.
+     * @param vals - A list of 16 values with indices corresponding to
+     * the FADC channel with which they are associated.
      */
     private void parseFADC(int crate, String key, List<String> vals) {
-    	// System.out.println(crate);
-        if (key.equals("FADC250_SLOT")) {
+    	// The FADC slot is not stored on the same line as the other
+    	// data and must be parsed and retained, as it is necessary
+    	// for handling the subsequent lines. If this line is the
+    	// FADC slot, store it.
+        if(key.equals("FADC250_SLOT")) {
             thisFadcSlot = Integer.valueOf(vals.get(0));
         }
-        else if (key.equals("FADC250_ALLCH_TET")) {
+        
+        // Parse the channel thresholds.
+        else if(key.equals("FADC250_ALLCH_TET")) {
             setChannelParsInt(crate, thisFadcSlot, THRESHOLD, vals);
         }
-        else if (key.equals("FADC250_ALLCH_PED")) {
+        
+        // Parse the channel pedestals.
+        else if(key.equals("FADC250_ALLCH_PED")) {
             setChannelParsFloat(crate, thisFadcSlot, PEDESTAL, vals);    
         }
-        else if (key.equals("FADC250_ALLCH_GAIN")) {
+        
+        // Parse the channel gains.
+        else if(key.equals("FADC250_ALLCH_GAIN")) {
             setChannelParsFloat(crate, thisFadcSlot, GAIN, vals);
         }
     }
     
-    private void setChannelParsFloat(int crate, int slot, Map<EcalChannel, Float>map, List<String> vals) {
-        for (int ii = 0; ii < 16; ii++) {
-            map.put(findChannel(crate, slot, ii),Float.valueOf(vals.get(ii)));
-        }
-    }
-    
-    private void setChannelParsInt(int crate, int slot, Map<EcalChannel, Integer>map, List<String> vals) {
-        for (int ii = 0; ii < 16; ii++) {
-            map.put(findChannel(crate, slot, ii),Integer.valueOf(vals.get(ii)));
-        }
-    }
-    
+    /**
+     * Takes a list of 16 values (in argument <code>vals</code>) and
+     * maps the appropriate database calorimeter channel to the list
+     * value. This assumes that the <code>String</code> values should
+     * be parsed to <code>Float</code> objects.
+     * @param crate - The calorimeter crate associated with the values.
+     * @param slot - The FADC slot associated with the values.
+     * @param map - The map in which to place the values.
+     * @param vals - A <code>List</code> of 16 <code>String</code>
+     * objects representing the channel values. This should correspond
+     * to FADC channels 0 - 15.
+     */
+    private void setChannelParsFloat(int crate, int slot, Map<EcalChannel, Float> map, List<String> vals) {
+    	// Iterate over each channel and map the database channel object
+    	// to the corresponding list value.
+        for(int ii = 0; ii < 16; ii++) {
+            map.put(findChannel(crate, slot, ii), Float.valueOf(vals.get(ii)));
+        }
+    }
+    
+    /**
+     * Takes a list of 16 values (in argument <code>vals</code>) and
+     * maps the appropriate database calorimeter channel to the list
+     * value. This assumes that the <code>String</code> values should
+     * be parsed to <code>Integer</code> objects.
+     * @param crate - The calorimeter crate associated with the values.
+     * @param slot - The FADC slot associated with the values.
+     * @param map - The map in which to place the values.
+     * @param vals - A <code>List</code> of 16 <code>String</code>
+     * objects representing the channel values.
+     */
+    private void setChannelParsInt(int crate, int slot, Map<EcalChannel, Integer> map, List<String> vals) {
+    	// Iterate over each channel and map the database channel object
+    	// to the corresponding list value.
+        for(int ii = 0; ii < 16; ii++) {
+            map.put(findChannel(crate, slot, ii), Integer.valueOf(vals.get(ii)));
+        }
+    }
+    
+    /**
+     * Prints the mapped parameter keys and values to the terminal.
+     */
     public void printMap() {
         System.out.print("\nTriggerConfigMap::::::::::::::::::::::::::::\n");
         for (String key : configMap.keySet()) {
@@ -285,8 +490,10 @@
         System.out.println("::::::::::::::::::::::::::::::::::::::::::::");
     }
     
-    public void printVars()
-    {
+    /**
+     * Prints the parsed parameter values to the terminal.
+     */
+    public void printVars() {
         System.out.println("\nTriggerConfigVars%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
         System.out.println();
         System.out.println(String.format("GTPMINSEED: %d",     gtpMinSeedEnergy));
@@ -300,7 +507,6 @@
         System.out.println(String.format("FADC250_WIDTH: %d",  fadcWIDTH));
         System.out.println(String.format("FADC250_OFFSET: %d", fadcOFFSET));
         for(EcalChannel cc : ecalConditions.getChannelCollection()) {
-            //System.out.print(String.format("SLOT%d CHAN%d --",cc.getSlot(),cc.getChannel()));
             if(!PEDESTAL.containsKey(cc)) {
                 System.out.println("\nP !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
             }
@@ -310,8 +516,6 @@
             if(!GAIN.containsKey(cc)) {
                 System.out.println("\nG !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
             }
-            //System.out.println(String.format(" %f %d %f",
-            //        PEDESTAL.get(cc),THRESHOLD.get(cc),GAIN.get(cc)));
         }
         
         System.out.println();
@@ -345,55 +549,138 @@
         System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
     }
     
-    /*
-     * Parsing wrappers to make rest of code easier.
+    /**
+     * Gets an SSP parameter value using a shortened version of the
+     * full parameter key and parses it as a <code>float</code>.
+     * @param itrig - The number of the trigger for which to obtain
+     * the parameter value.
+     * @param stub - The shortened version of the parameter key. This
+     * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]".
+     * @param ival - The index of the value that is to be obtained.
+     * @return Returns the requested value if it exists. Otherwise, a
+     * value of <code>0</code> is returned and a message is logged.
      */
     public float getFloatConfigSSP(int itrig, String stub, int ival) {
         return Float.valueOf(getConfigSSP(itrig, stub, ival));
     }
     
+    /**
+     * Gets an SSP parameter value using a shortened version of the
+     * full parameter key and parses it as a <code>int</code>.
+     * @param itrig - The number of the trigger for which to obtain
+     * the parameter value.
+     * @param stub - The shortened version of the parameter key. This
+     * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]".
+     * @param ival - The index of the value that is to be obtained.
+     * @return Returns the requested value if it exists. Otherwise, a
+     * value of <code>0</code> is returned and a message is logged.
+     */
     public int getIntConfigSSP(int itrig, String stub, int ival) {
         return Integer.valueOf(getConfigSSP(itrig, stub, ival));
     }
     
+    /**
+     * Gets an SSP parameter value using a shortened version of the
+     * full parameter key and parses it as a <code>boolean</code>.
+     * @param itrig - The number of the trigger for which to obtain
+     * the parameter value.
+     * @param stub - The shortened version of the parameter key. This
+     * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]".
+     * @param ival - The index of the value that is to be obtained.
+     * @return Returns the requested value if it exists. Otherwise, a
+     * value of <code>false</code> is returned and a message is logged.
+     */
     public boolean getBoolConfigSSP(int itrig, String stub, int ival) {
         return "1".equals(getConfigSSP(itrig, stub, ival));
     }
     
+    /**
+     * Gets an SSP parameter value using a shortened version of the
+     * full parameter key.
+     * @param itrig - The number of the trigger for which to obtain
+     * the parameter value.
+     * @param stub - The shortened version of the parameter key. This
+     * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]".
+     * @param ival - The index of the value that is to be obtained.
+     * @return Returns the requested value if it exists. Otherwise, a
+     * value of <code>"0"</code> is returned and a message is logged.
+     */
     public String getConfigSSP(int itrig, String stub, int ival) {
         String key = "SSP_HPS_" + stub + "_" + itrig;
-        return getConfig(key,ival);
-    }
-    
-    public String getConfig(String key, int ival) {
-        if (configMap.containsKey(key)) {
+        return getConfigParameter(key, ival);
+    }
+    
+    /**
+     * Gets a parameter value associated with a parameter key.
+     * @param key - The parameter key to which the value belongs.
+     * @param ival - The index of the desired parameter value.
+     * @return Returns the requested parameter value if it exists and
+     * returns <code>"0"</code> otherwise. In the event that a parameter
+     * can not be found, an error message is passed to the logger.
+     */
+    public String getConfigParameter(String key, int ival) {
+    	// Check the parameter map for the requested parameter key.
+        if(configMap.containsKey(key)) {
+        	// Get the list of values associated with this parameter key.
             List<String> vals = configMap.get(key);
-            if (ival < vals.size()) {
-                return configMap.get(key).get(ival);
-            } else {
-                Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
-                        "ConfigMap TOO SHORT:   " + ival + " " + configMap.get(key));
+            
+            // Check that the list of values contains a parameter for
+            // the requested parameter index. If it does, return it.
+            if (ival < vals.size()) { return configMap.get(key).get(ival); }
+            
+            // Otherwise, an error has occurred. Log this and return the
+            // default value of zero.
+            else {
+                Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "ConfigMap TOO SHORT:   " + ival + " " + configMap.get(key));
                 return "0";
             }
-        } else {
-            // this is only necessarily an error if we've read 3 banks:
+        }
+        
+        // If the key is not present...
+        else {
+            // If more than 2 banks have been read, the absence of a
+        	// key represents an error. Log that this has occurred.
             if(nBanks > 2) {
                 Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "ConfigMap MISSING KEY:   " + key);
             }
+            
+            // Return a default value of zero.
             return "0";
         }
     }
     
+    /**
+     * Gets the database calorimeter channel for a channel defined by
+     * a crate number, FADC slot, and FADC channel.
+     * @param crate - The crate number.
+     * @param fadcSlot - The FADC slot.
+     * @param fadcChan - The FADC channel.
+     * @return Returns the database channel as a <code>EcalChannel</code>
+     * if it exists, and <code>null</code> if it does not.
+     */
     public EcalChannel findChannel(int crate, int fadcSlot, int fadcChan) {
+    	// Search through the database channels for a channel that
+    	// matches the the argument parameters.
         for (EcalChannel cc : channels) {
-            // EcalChannel follows different convention on crate numbering:
-            if ((cc.getCrate() - 1) * 2 == crate - 37 && cc.getSlot() == fadcSlot && cc.getChannel() == fadcChan) {
+        	// A channel matches the argument if the slot and channel
+        	// values are the same. Crate number must also match, but
+        	// note that EcalChannel follows a different convention
+        	// with respect to crate numbering.
+            if( ((cc.getCrate() - 1) * 2 == crate - 37) && (cc.getSlot() == fadcSlot) && (cc.getChannel() == fadcChan) ) {
                 return cc;
             }
         }
+        
+        // If no matching channel is found, return null.
         return null;
     }
     
+    /**
+     * Gets the database crystal channel object based on the crystal's
+     * numerical index.
+     * @param channel_id - The crystal index.
+     * @return Returns the channel as an <code>EcalChannel</code>.
+     */
     public EcalChannel findChannel(int channel_id) {
         return ecalConditions.getChannelCollection().findChannel(channel_id);
     }

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java	Thu Aug  6 17:19:42 2015
@@ -4,57 +4,64 @@
 import org.lcsim.event.GenericObject;
 
 /**
- * GenericObject representation of an INT32/UINT32 bank read from EVIO. The bank
- * header tag identifies the type of data, and is stored as the first int in the
- * GenericObject. The contents of the bank are the remaining N-1 ints.
- * Constructors are provided from int[] (for reading from EVIO) and from
- * GenericObject (for reading from LCIO).
- *
+ * Class <code>GenericObject</code> representation of an INT32/UINT32
+ * bank read from EvIO. The bank header tag identifies the type of
+ * data, and is stored as the first int in the <code>GenericObject</code>.
+ * The contents of the bank are the remaining N-1 <code>int</code>
+ * primitives. Constructors are provided from <code>int[]</code> (for
+ * reading from EvIO) and from <code>GenericObject</code> (for reading
+ * from LCIO).<br/>
+ * <br/>
  * Subclasses must implement the two constructors and two abstract methods, plus
  * whatever methods are needed to access the parsed data.
  *
  * @author Sho Uemura <[log in to unmask]>
- * @version $Id: $
+ * @see GenericObject
  */
 public abstract class AbstractIntData implements GenericObject {
-
+	/** The data bank. */
     protected int[] bank;
-
+    
     /**
-     * Constructor from EVIO int bank. Bank tag must be checked by EVIO reader
-     * before the constructor is called.
-     *
-     * @param bank
+     * Constructs an <code>AbstractIntData</code> from a raw EvIO integer
+     * bank. It is expected that the EvIO reader will verify that the
+     * bank tag is the appropriate type before calling the constructor.
+     * @param bank - An EvIO bank of <code>int</code> data.
      */
     protected AbstractIntData(int[] bank) {
-        if (bank == null) {
-            this.bank = new int[0];
-        } else {
-            this.bank = Arrays.copyOf(bank, bank.length);
-        }
+        if(bank == null) { this.bank = new int[0]; }
+        else { this.bank = Arrays.copyOf(bank, bank.length); }
     }
-
+    
     /**
-     * Constructor from LCIO GenericObject. Checks the bank tag; subclass
-     * constructor must set the expected value of the tag.
-     *
-     * @param data
-     * @param expectedTag
+     * Create an <code>AbstractIntData</code> object from an LCIO
+     * <code>genericObject</code>. Constructor requires that the
+     * <code>GenericObject</code> tag match the expected EvIO header
+     * tag type as defined by the implementing class.
+     * @param data - The source data bank.
+     * @param expectedTag - The required EvIO bank header tag.
      */
     protected AbstractIntData(GenericObject data, int expectedTag) {
-        if (getTag(data) != expectedTag) {
+    	// If the EvIO bank header tag is not the required type,
+    	// produce an exception.
+        if(getTag(data) != expectedTag) {
             throw new RuntimeException("expected tag " + expectedTag + ", got " + getTag(data));
         }
+        
+        // Otherwise, store the bank.
         this.bank = getBank(data);
     }
-
+    
+    /**
+     * Gets the entire, unparsed integer data bank from the object.
+     * @return Returns the data as an <code>int[]</code> array.
+     */
     public int[] getBank() {
         return bank;
     }
-
+    
     /**
      * Return the int bank of an AbstractIntData read from LCIO.
-     *
      * @param object
      * @return
      */
@@ -66,55 +73,55 @@
         }
         return bank;
     }
-
+    
     /**
-     * Return a single value from the int bank of an AbstractIntData.
-     *
-     * @param object
-     * @param index
-     * @return
+     * Return a single value from the integer bank of an
+     * <code>AbstractIntData</code>.
+     * @param object - The bank from which to obtain the data.
+     * @param index - The index of the data in the bank.
+     * @return Returns the requested entry from the integer bank.
      */
     public static int getBankInt(GenericObject object, int index) {
         return object.getIntVal(index + 1);
     }
-
+    
     /**
-     * Returns the EVIO bank header tag expected for this data.
-     *
-     * @return
+     * Returns the EvIO bank header tag expected for this data.
+     * @return Returns the tag as an <code>int</code> primitive.
      */
     public abstract int getTag();
-
+    
     /**
      * Returns the EVIO bank tag for a data object.
-     *
-     * @param data
-     * @return
+     * @param data - A <code>GenericObject</code> representing an integer
+     * data bank.
+     * @return Returns the EvIO tag identifying the type of bank the object
+     * represents.
      */
     public static int getTag(GenericObject data) {
         return data.getIntVal(0);
     }
-
+    
     /**
      * Parses the bank so the object can be used in analysis.
      */
     protected abstract void decodeData();
-
+    
     @Override
     public int getNInt() {
         return bank.length + 1;
     }
-
+    
     @Override
     public int getNFloat() {
         return 0;
     }
-
+    
     @Override
     public int getNDouble() {
         return 0;
     }
-
+    
     @Override
     public int getIntVal(int index) {
         if (index == 0) {
@@ -122,19 +129,19 @@
         }
         return bank[index - 1];
     }
-
+    
     @Override
     public float getFloatVal(int index) {
         throw new UnsupportedOperationException("No float values in " + this.getClass().getSimpleName());
     }
-
+    
     @Override
     public double getDoubleVal(int index) {
         throw new UnsupportedOperationException("No double values in " + this.getClass().getSimpleName());
     }
-
+    
     @Override
     public boolean isFixedSize() {
         return true;
     }
-}
+}

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java	Thu Aug  6 17:19:42 2015
@@ -7,7 +7,14 @@
 
 /**
  * Class <code>SSPCluster</code> stores all of the information on 
- * clusters that is reported by the SSP.
+ * clusters that is reported by the SSP. SSP clusters store:
+ * <ul><li>Cluster center x-index</li>
+ * <li>Cluster center y-index</li>
+ * <li>Cluster total energy</li>
+ * <li>Cluster hit count</li>
+ * <li>Cluster time</li></ul>
+ * <code>SSPCluster</code> does not support the ability to track
+ * individual hits that are part of a cluster.
  * 
  * @author Kyle McCarty <[log in to unmask]>
  */

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java	Thu Aug  6 17:19:42 2015
@@ -2,17 +2,22 @@
 
 import org.lcsim.event.GenericObject;
 
-//import org.hps.record.evio.EvioEventConstants; // doesn't work
 /**
- * TI Trigger Data
+ * Class <code>TIData</code> is an implementation of abstract class
+ * <code>AbstractIntData</code> that represents a TI trigger bit bank.
+ * It contains both a time window length and a set of flags that track
+ * whether a trigger of a given type was registered with the event to
+ * which this bank is attached.
  *
  * @author Nathan Baltzell <[log in to unmask]>
  */
 public class TIData extends AbstractIntData {
-
+	/** The EvIO bank header tag for TI data banks. */
     public static final int BANK_TAG = 0xe10a; // EvioEventConstants.TI_TRIGGER_BANK_TAG;
+    /** The expected number of entries in the data bank. */
     public static final int BANK_SIZE = 4;
-
+    
+    // Store the parsed data bank parameters.
     private long time = 0;
     private boolean singles0 = false;
     private boolean singles1 = false;
@@ -20,69 +25,122 @@
     private boolean pairs1 = false;
     private boolean calib = false;
     private boolean pulser = false;
-
+    
+    /**
+     * Creates a <code>TIData</code> bank from a raw EvIO data bank.
+     * It is expected that the EvIO reader will verify that the bank
+     * tag is of the appropriate type.
+     * @param bank - The EvIO data bank.
+     */
     public TIData(int[] bank) {
         super(bank);
         decodeData();
     }
-
+    
+    /**
+     * Creates a <code>TIData</code> object from an existing LCIO
+     * <code>GenericObject</code>.
+     * @param tiData - The source data bank object.
+     */
     public TIData(GenericObject tiData) {
         super(tiData, BANK_TAG);
         decodeData();
     }
-
+    
     @Override
     protected final void decodeData() {
-        if (this.bank.length != BANK_SIZE) {
+    	// Check that the data bank is the expected size. If not, throw
+    	// and exception.
+        if(this.bank.length != BANK_SIZE) {
             throw new RuntimeException("Invalid Data Length:  " + bank.length);
         }
-
+        
+        // Check each trigger bit to see if it is active. A value of 
+        // 1 indicates a trigger of that type occurred, and 0 that it
+        // did not.
         singles0 = ((bank[0] >> 24) & 1) == 1;
         singles1 = ((bank[0] >> 25) & 1) == 1;
         pairs0 = ((bank[0] >> 26) & 1) == 1;
         pairs1 = ((bank[0] >> 27) & 1) == 1;
         calib = ((bank[0] >> 28) & 1) == 1;
         pulser = ((bank[0] >> 29) & 1) == 1;
-
+        
+        // Get the unprocessed start and end times for the bank.
         long w1 = bank[2] & 0xffffffffL;
         long w2 = bank[3] & 0xffffffffL;
-
+        
+        // Process the times into units of clock-cycles.
         final long timelo = w1;
         final long timehi = (w2 & 0xffff) << 32;
-
-        time = 4 * (timelo + timehi); // units ns
+        
+        // Store the time difference in nanoseconds.
+        time = 4 * (timelo + timehi);
     }
-
+    
     @Override
     public int getTag() {
         return BANK_TAG;
     }
-
+    
+    /**
+     * Gets the time window for the bank.
+     * @return Returns the time window length in nanoseconds.
+     */
     public long getTime() {
         return time;
     }
-
+    
+    /**
+     * Indicates whether a singles 0 trigger was registered.
+     * @return Returns <code>true</code> if the trigger occurred, and
+     * <code>false</code> otherwise.
+     */
     public boolean isSingle0Trigger() {
         return singles0;
     }
-
+    
+    /**
+     * Indicates whether a singles 1 trigger was registered.
+     * @return Returns <code>true</code> if the trigger occurred, and
+     * <code>false</code> otherwise.
+     */
     public boolean isSingle1Trigger() {
         return singles1;
     }
-
+    
+    /**
+     * Indicates whether a pair 0 trigger was registered.
+     * @return Returns <code>true</code> if the trigger occurred, and
+     * <code>false</code> otherwise.
+     */
     public boolean isPair0Trigger() {
         return pairs0;
     }
-
+    
+    /**
+     * Indicates whether a pair 1 trigger was registered.
+     * @return Returns <code>true</code> if the trigger occurred, and
+     * <code>false</code> otherwise.
+     */
     public boolean isPair1Trigger() {
         return pairs1;
     }
-
+    
+    /**
+     * Indicates whether a cosmic trigger was registered.
+     * @return Returns <code>true</code> if the trigger occurred, and
+     * <code>false</code> otherwise.
+     */
     public boolean isCalibTrigger() {
         return calib;
     }
-
+    
+    /**
+     * Indicates whether a random/pulser trigger was registered.
+     * @return Returns <code>true</code> if the trigger occurred, and
+     * <code>false</code> otherwise.
+     */
     public boolean isPulserTrigger() {
         return pulser;
     }
-}
+}

Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java
 =============================================================================
--- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java	(original)
+++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java	Thu Aug  6 17:19:42 2015
@@ -20,62 +20,85 @@
  * called without initializing an instance of the module.<br/>
  * <br/>
  * Both <code>Cluster</code> objects and <code>SSPCluster</code> objects
- * are supported.
- * 
+ * are supported, except for the seed energy cut, as this value is not
+ * present in <code>SSPCluster</code> objects.<br/>
+ * <br/>
+ * This module supports the following cuts:
+ * <ul><li>Seed Energy Lower Bound</li>
+ * <li>Seed Energy Lower Bound</li>
+ * <li>Seed Energy Upper Bound</li>
+ * <li>Cluster Total Energy Upper Bound</li>
+ * <li>Cluster Total Energy Lower Bound</li>
+ * <li>Cluster Hit Count Lower Bound</li>
+ * <li>Pair Energy Sum Upper Bound</li>
+ * <li>Pair Energy Sum Lower Bound</li>
+ * <li>Pair Energy Difference Upper Bound</li>
+ * <li>Pair Energy Slope Lower Bound</li>
+ * <li>Pair Coplanarity Upper Bound</li>
+ * <li>Pair Time Coincidence Upper Bound</li></ul>
  * @author Kyle McCarty <[log in to unmask]>
  * @see Cluster
  * @see SSPCluster
  */
 public final class TriggerModule {
-	// The calorimeter mid-plane, defined by the photon beam position
-	// (30.52 mrad) at the calorimeter face (z = 1393 mm).
+	/** The calorimeter mid-plane, defined by the photon beam position
+	* (30.52 mrad) at the calorimeter face (z = 1393 mm). */
     private static final double ORIGIN_X = 1393.0 * Math.tan(0.03052);
     
-    // Trigger module property names.
     /** The value of the parameter "F" in the energy slope equation
-     * <code>E_low GeV + R_min mm * F GeV/mm</code>. */
+     * <code>E_low GeV + R_min mm * F GeV/mm</code>. Units are in GeV
+     * / mm. */
     public static final String PAIR_ENERGY_SLOPE_F = "pairEnergySlopeF";
     /** The lower bound for the pair energy sum cut. The sum of the
-     * energies of two clusters must exceed this value to pass the cut. */
+     * energies of two clusters must exceed this value to pass the cut.
+     * Units are in GeV. */
     public static final String PAIR_ENERGY_SUM_LOW = "pairEnergySumLow";
     /** The upper bound for the pair energy sum cut. The sum of the
-     * energies of two clusters must be below this value to pass the cut. */
+     * energies of two clusters must be below this value to pass the
+     * cut. Units are in GeV. */
     public static final String PAIR_ENERGY_SUM_HIGH = "pairEnergySumHigh";
     /** The threshold for the cluster hit count cut. Clusters must have
      * this many hits or more to pass the cut. */
     public static final String CLUSTER_HIT_COUNT_LOW = "clusterHitCountLow";
     /** The threshold for the energy slope cut. The value of the energy
-     * slope equation must exceed this value to pass the cut. */
+     * slope equation must exceed this value to pass the cut. Units are
+     * in GeV. */
     public static final String PAIR_ENERGY_SLOPE_LOW = "pairEnergySlopeLow";
     /** The bound for the coplanarity cut. The coplanarity angle for
-     * the cluster pair must be below this value to pass the cut. */
+     * the cluster pair must be below this value to pass the cut. Units
+     * are in degrees. */
     public static final String PAIR_COPLANARITY_HIGH = "pairCoplanarityHigh";
     /** The lower bound for the cluster seed energy cut. The seed energy
-     * of a cluster must exceed this value to pass the cut. */
+     * of a cluster must exceed this value to pass the cut. Units are in
+     * GeV. */
     public static final String CLUSTER_SEED_ENERGY_LOW = "clusterSeedEnergyLow";
     /** The upper bound for the cluster seed energy cut. The seed energy
-     * of a cluster must be below this value to pass the cut. */
+     * of a cluster must be below this value to pass the cut. Units are
+     * in GeV. */
     public static final String CLUSTER_SEED_ENERGY_HIGH = "clusterSeedEnergyHigh";
     /** The lower bound for the cluster total energy cut. The energy
      * of a cluster must exceed this value to pass the cut. */
     public static final String CLUSTER_TOTAL_ENERGY_LOW = "clusterTotalEnergyLow";
     /** The upper bound for the cluster total energy cut. The energy
-     * of a cluster must be below this value to pass the cut. */
+     * of a cluster must be below this value to pass the cut. Units are
+     * in GeV. */
     public static final String CLUSTER_TOTAL_ENERGY_HIGH = "clusterTotalEnergyHigh";
     /** The bound for the pair energy difference cut. The absolute value
      * of the difference between the energies of the cluster pair must
-     * be below this value to pass the cut. */
+     * be below this value to pass the cut. Units are in GeV. */
     public static final String PAIR_ENERGY_DIFFERENCE_HIGH = "pairEnergyDifferenceHigh";
     /** The maximum amount of time by which two clusters are allowed
-     * to be separated. */
+     * to be separated. Units are in ns. */
     public static final String PAIR_TIME_COINCIDENCE = "pairTimeCoincidence";
     
-    // Trigger cut settings map.
+    /** Stores each of the cut values used by the module. Map keys are
+     * defined as publicly-accessible static variables in the class. */
     private final Map<String, Double> cuts = new HashMap<String, Double>(11);
     
     /**
-     * Creates an <code>SSPTriggerModule</code> that accepts all single
-     * cluster and cluster pair events.
+     * Creates a default <code>TriggerModule</code>. The cuts are
+     * defined such that all physical clusters (i.e. with energy
+     * above zero) will be accepted.
      */
     public TriggerModule() {
     	// Set the cluster singles cuts to accept all values by default.
@@ -98,21 +121,21 @@
     }
     
     /**
-     * Creates an <code>SSPTriggerModule</code> that uses the default
-     * cut values specified by the argument array. The array should be
-     * of size 11. Values are applied in the order:
+     * Creates a <code>TriggerModule</code> with trigger cuts defined
+     * by the argument array. The order of the cut value arguments are
+     * as follows:
      * <ul>
-     * <li>Cluster Hit Count Lower Bound</li>
-     * <li>Cluster Seed Energy Lower Bound</li>
-     * <li>Cluster Seed Energy Upper Bound</li>
-     * <li>Cluster Seed Total Lower Bound</li>
-     * <li>Cluster Seed Total Upper Bound</li>
-     * <li>Pair Energy Sum Lower Bound</li>
-     * <li>Pair Energy Sum Upper Bound</li>
-     * <li>Pair Energy Difference Upper Bound</li>
-     * <li>Pair Energy Slope Lower Bound</li>
-     * <li>Pair Coplanarity Upper Bound</li>
-     * <li>Pair Energy Slope Parameter F</li>
+     * <li>Cluster Hit Count Lower Bound (Hits)</li>
+     * <li>Cluster Seed Energy Lower Bound (GeV)</li>
+     * <li>Cluster Seed Energy Upper Bound (GeV)</li>
+     * <li>Cluster Seed Total Lower Bound (GeV)</li>
+     * <li>Cluster Seed Total Upper Bound (GeV)</li>
+     * <li>Pair Energy Sum Lower Bound (GeV)</li>
+     * <li>Pair Energy Sum Upper Bound (GeV)</li>
+     * <li>Pair Energy Difference Upper Bound (GeV)</li>
+     * <li>Pair Energy Slope Lower Bound (GeV)</li>
+     * <li>Pair Coplanarity Upper Bound (Degrees)</li>
+     * <li>Pair Energy Slope Parameter F (GeV / mm)</li>
      * </ul>
      */
     public TriggerModule(double... cutValues) {
@@ -139,9 +162,11 @@
     
     /**
      * Gets the value of the requested cut, if it exists.
-     * @param cut - The identifier of the cut.
+     * @param cut - The identifier of the cut. This can be obtained
+     * through the publicly-accessible static identifiers in this class.
      * @return Returns the cut value as a <code>double</code>.
-     * @throws IllegalArgumentException Occurs if the cut does not exist.
+     * @throws IllegalArgumentException Occurs if the cut identifier
+     * specified in the argument is not valid.
      */
     public double getCutValue(String cut) throws IllegalArgumentException {
     	// Try to get the indicated cut.
@@ -156,8 +181,9 @@
     
     /**
      * Loads triggers settings from the DAQ configuration for a singles
-     * trigger. Pair trigger settings will be set to accept all possible
-     * values, while singles trigger settings will
+     * trigger. Singles trigger cuts will be set to match those defined
+     * in the configuration object, while pair trigger cuts will be set
+     * to accept all possible clusters.
      * @param config - The DAQ configuration settings.
      */
     public void loadDAQConfiguration(SinglesTriggerConfig config) {
@@ -205,11 +231,14 @@
     }
     
     /**
-     * Sets the value of the indicated cut to a new value.
+     * Sets the value of the cut specified by the identifier given in
+     * the argument to the specified value.
      * @param cut - The identifier of the cut to which the new value
-     * should be assigned.
+     * should be assigned. These can be obtained as publicly-accessible
+     * static variables from this class.
      * @param value - The new cut value.
-     * @throws IllegalArgumentException Occurs if the cut does not exist.
+     * @throws IllegalArgumentException Occurs if the argument cut
+     * identifier is not valid.
      */
     public void setCutValue(String cut, double value) throws IllegalArgumentException {
     	// Make sure that the cut exists. If it does, change it to the
@@ -230,6 +259,7 @@
 	 * @param cutValues - A string representing the cuts values. This
 	 * must be formatted in the style of "Emin Emax Nmin ...".
 	 */
+    // TODO: Specify in JavaDoc what the order of these arguments is.
 	public void setCutValues(boolean isSingles, String cutValues) {
 		// Make sure that the string is not null.
 		if(cutValues == null) {
@@ -283,8 +313,8 @@
 	}
     
     /**
-     * Checks whether the argument cluster possesses the minimum
-     * allowed hits.
+     * Checks whether a cluster passes the cluster hit count cut. This
+     * is defined as <code>N_hits >= CLUSTER_HIT_COUNT_LOW</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -294,8 +324,8 @@
     }
     
     /**
-     * Checks whether the argument cluster possesses the minimum
-     * allowed hits.
+     * Checks whether a cluster passes the cluster hit count cut. This
+     * is defined as <code>N_hits >= CLUSTER_HIT_COUNT_LOW</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -305,8 +335,9 @@
     }
     
     /**
-     * Checks whether the argument cluster seed hit falls within the
-     * allowed seed hit energy range.
+     * Checks whether a cluster passes the seed energy cut. This is
+     * defined as <code>CLUSTER_SEED_ENERGY_LOW <= E_seed <=
+     * CLUSTER_SEED_ENERGY_HIGH</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -316,8 +347,8 @@
     }
     
     /**
-     * Checks whether the argument cluster seed hit falls below the
-     * allowed seed hit energy upper bound.
+     * Checks whether a cluster passes the seed energy upper bound cut.
+     * This is defined as <code>E_seed <= CLUSTER_SEED_ENERGY_HIGH</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -327,8 +358,8 @@
     }
     
     /**
-     * Checks whether the argument cluster seed hit falls above the
-     * allowed seed hit energy lower bound.
+     * Checks whether a cluster passes the seed energy lower bound cut.
+     * This is defined as <code>CLUSTER_SEED_ENERGY_LOW <= E_seed</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -338,8 +369,9 @@
     }
     
     /**
-     * Checks whether the argument cluster falls within the allowed
-     * cluster total energy range.
+     * Checks whether a cluster passes the cluster total energy cut.
+     * This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <= E_cluster
+     * <= CLUSTER_TOTAL_ENERGY_HIGH</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -349,8 +381,9 @@
     }
     
     /**
-     * Checks whether the argument cluster falls below the allowed
-     * cluster total energy upper bound.
+     * Checks whether a cluster passes the cluster total energy upper
+     * bound cut. This is defined as <code>E_cluster <=
+     * CLUSTER_TOTAL_ENERGY_HIGH</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -360,8 +393,9 @@
     }
     
     /**
-     * Checks whether the argument cluster falls above the allowed
-     * cluster total energy lower bound.
+     * Checks whether a cluster passes the cluster total energy lower
+     * bound cut. This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <=
+     * E_cluster</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -371,8 +405,9 @@
     }
     
     /**
-     * Checks whether the argument cluster falls within the allowed
-     * cluster total energy range.
+     * Checks whether a cluster passes the cluster total energy cut.
+     * This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <= E_cluster
+     * <= CLUSTER_TOTAL_ENERGY_HIGH</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -382,8 +417,9 @@
     }
     
     /**
-     * Checks whether the argument cluster falls below the allowed
-     * cluster total energy upper bound.
+     * Checks whether a cluster passes the cluster total energy upper
+     * bound cut. This is defined as <code>E_cluster <=
+     * CLUSTER_TOTAL_ENERGY_HIGH</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -393,8 +429,9 @@
     }
     
     /**
-     * Checks whether the argument cluster falls above the allowed
-     * cluster total energy lower bound.
+     * Checks whether a cluster passes the cluster total energy lower
+     * bound cut. This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <=
+     * E_cluster</code>.
      * @param cluster - The cluster to check.
      * @return Returns <code>true</code> if the cluster passes the cut
      * and <code>false</code> if the cluster does not.
@@ -409,6 +446,7 @@
      * be calculated.
      * @return Returns displacement of the cluster.
      */
+    // TODO: What defines cluster distance?
     public static double getClusterDistance(Cluster cluster) {
     	// Get the variables from the cluster.
     	double x = getClusterX(cluster);
@@ -419,12 +457,23 @@
     }
     
     /**
-     * Gets the size of a cluster.
+     * Gets the number of hits in a cluster, as used in the cluster
+     * hit count cut.
      * @param cluster - The cluster for which to obtain the size.
      * @return Returns the size as an <code>int</code>.
      */
     public static final double getClusterHitCount(Cluster cluster) {
     	return cluster.getCalorimeterHits().size();
+    }
+    
+    /**
+     * Gets the number of hits in a cluster, as used in the cluster
+     * hit count cut.
+     * @param cluster - The cluster for which to obtain the size.
+     * @return Returns the size as an <code>int</code>.
+     */
+    public static final double getClusterHitCount(SSPCluster cluster) {
+    	return cluster.getHitCount();
     }
     
     /**
@@ -442,12 +491,23 @@
     }
     
     /**
-     * Gets the time-stamp of a cluster.
+     * Gets the time-stamp of a cluster, as used in the time-coincidence
+     * cut.
      * @param cluster - The cluster for which to obtain the time.
      * @return Returns the time as a <code>double</code>.
      */
     public static final double getClusterTime(Cluster cluster) {
     	return getClusterSeedHit(cluster).getTime();
+    }
+    
+    /**
+     * Gets the time-stamp of a cluster, as used in the time-coincidence
+     * cut.
+     * @param cluster - The cluster for which to obtain the time.
+     * @return Returns the time as a <code>double</code>.
+     */
+    public static final double getClusterTime(SSPCluster cluster) {
+    	return cluster.getTime();
     }
     
     /**
@@ -471,12 +531,21 @@
     }
     
     /**
-     * Gets the x-index of a cluster.
+     * Gets the x-index of a cluster's
      * @param cluster - The cluster for which to obtain the index.
      * @return Returns the index as an <code>int</code>.
      */
     public static final int getClusterXIndex(Cluster cluster) {
     	return getClusterSeedHit(cluster).getIdentifierFieldValue("ix");
+    }
+    
+    /**
+     * Gets the x-index of a cluster's
+     * @param cluster - The cluster for which to obtain the index.
+     * @return Returns the index as an <code>int</code>.
+     */
+    public static final int getClusterXIndex(SSPCluster cluster) {
+    	return cluster.getXIndex();
     }
     
     /**
@@ -509,6 +578,15 @@
     }
     
     /**
+     * Gets the y-index of a cluster.
+     * @param cluster - The cluster for which to obtain the index.
+     * @return Returns the index as an <code>int</code>.
+     */
+    public static final int getClusterYIndex(SSPCluster cluster) {
+    	return cluster.getYIndex();
+    }
+    
+    /**
      * Gets the z-position of a cluster in millimeters in the hardware
      * coordinate system.
      * @param cluster - The cluster of which to get the z-position.
@@ -529,27 +607,30 @@
     }
     
     /**
-     * Gets the value used for the cluster total energy cut.
+     * Gets the value used for the cluster total energy cut. This is
+     * the energy of the entire cluster.
      * @param cluster - The cluster from which the value should be
      * derived.
-     * @return Returns the energy of the entire cluster in GeV.
+     * @return Returns the cluster energy in GeV.
      */
     public static double getValueClusterTotalEnergy(Cluster cluster) {
         return cluster.getEnergy();
     }
     
     /**
-     * Gets the value used for the cluster total energy cut.
+     * Gets the value used for the cluster total energy cut. This is
+     * the energy of the entire cluster.
      * @param cluster - The cluster from which the value should be
      * derived.
-     * @return Returns the energy of the entire cluster in GeV.
+     * @return Returns the cluster energy in GeV.
      */
     public static double getValueClusterTotalEnergy(SSPCluster cluster) {
         return cluster.getEnergy();
     }
     
     /**
-     * Gets the value used for the cluster hit count cut.
+     * Gets the value used for the cluster hit count cut. This is the
+     * total number of hits included in the cluster.
      * @param cluster - The cluster from which the value should be
      * derived.
      * @return Returns the number of hits in the cluster.
@@ -559,7 +640,8 @@
     }
     
     /**
-     * Gets the value used for the cluster hit count cut.
+     * Gets the value used for the cluster hit count cut. This is the
+     * total number of hits included in the cluster.
      * @param cluster - The cluster from which the value should be
      * derived.
      * @return Returns the number of hits in the cluster.
@@ -587,14 +669,15 @@
     public static double getValueCoplanarity(Cluster[] clusterPair) {
     	// Get the variables used by the calculation.
     	double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) };
-    	double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) };
+    	double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) };
     	
     	// Return the calculated value.
-    	return getValueCoplanarity(x, z);
-    }
-    
-    /**
-     * Calculates the value used by the coplanarity cut.
+    	return getValueCoplanarity(x, y);
+    }
+    
+    /**
+     * Calculates the value used by the coplanarity cut. A value of zero
+     * represents clusters in the same plane.
      * @param clusterPair - The cluster pair from which the value should
      * be calculated.
      * @return Returns the cut value.
@@ -602,10 +685,10 @@
     public static double getValueCoplanarity(SSPCluster[] clusterPair) {
     	// Get the variables used by the calculation.
     	double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) };
-    	double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) };
+    	double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) };
     	
     	// Return the calculated value.
-    	return getValueCoplanarity(x, z);
+    	return getValueCoplanarity(x, y);
     }
     
     /**
@@ -667,10 +750,10 @@
     	// Get the variables used by the calculation.
     	double[] energy = { clusterPair[0].getEnergy(), clusterPair[1].getEnergy() };
     	double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) };
-    	double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) };
+    	double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) };
     	
     	// Perform the calculation.
-    	return getValueEnergySlope(energy, x, z, energySlopeParamF);
+    	return getValueEnergySlope(energy, x, y, energySlopeParamF);
     }
     
     /**
@@ -685,10 +768,10 @@
     	// Get the variables used by the calculation.
     	double[] energy = { clusterPair[0].getEnergy(), clusterPair[1].getEnergy() };
     	double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) };
-    	double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) };
+    	double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) };
     	
     	// Perform the calculation.
-    	return getValueEnergySlope(energy, x, z, energySlopeParamF);
+    	return getValueEnergySlope(energy, x, y, energySlopeParamF);
     }
     
     /**
@@ -773,7 +856,7 @@
     
     /**
      * Checks if a cluster pair is coplanar to the beam within a given
-     * angle.
+     * angle. This is defined as <code>θ <= PAIR_COPLANARITY_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -784,7 +867,7 @@
     
     /**
      * Checks if a cluster pair is coplanar to the beam within a given
-     * angle.
+     * angle. This is defined as <code>θ <= PAIR_COPLANARITY_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -795,7 +878,8 @@
     
     /**
      * Checks if the energy difference between the clusters making up
-     * a cluster pair is below an energy difference threshold.
+     * a cluster pair is below an energy difference threshold. This is
+     * defined as <code>|E_1 - E_2| <= PAIR_ENERGY_DIFFERENCE_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -806,7 +890,8 @@
     
     /**
      * Checks if the energy difference between the clusters making up
-     * a cluster pair is below an energy difference threshold.
+     * a cluster pair is below an energy difference threshold. This is
+     * defined as <code>|E_1 - E_2| <= PAIR_ENERGY_DIFFERENCE_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -818,7 +903,7 @@
     /**
      * Requires that the distance from the beam of the lowest energy
      * cluster in a cluster pair satisfies the following:<br/>
-     * <code>E_low + R_min * F < [ Threshold ]</code>
+     * <code>E_low + R_min * F >= PAIR_ENERGY_SLOPE_LOW</code>
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -830,7 +915,7 @@
     /**
      * Requires that the distance from the beam of the lowest energy
      * cluster in a cluster pair satisfies the following:<br/>
-     * <code>E_low + R_min * F < [ Threshold ]</code>
+     * <code>E_low + R_min * F >= PAIR_ENERGY_SLOPE_LOW</code>
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -841,7 +926,9 @@
     
     /**
      * Checks if the sum of the energies of the clusters making up a
-     * cluster pair is within an energy sum threshold.
+     * cluster pair is within an energy sum threshold. This is defined
+     * as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2 <=
+     * PAIR_ENERGY_SUM_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -853,6 +940,7 @@
     /**
      * Checks if the sum of the energies of the clusters making up a
      * cluster pair is below the energy sum upper bound threshold.
+     * This is defined as <code>E_1 + E_2 <= PAIR_ENERGY_SUM_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -864,6 +952,7 @@
     /**
      * Checks if the sum of the energies of the clusters making up a
      * cluster pair is above the energy sum lower bound threshold.
+     * This is defined as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -874,7 +963,9 @@
     
     /**
      * Checks if the sum of the energies of clusters making up a cluster
-     * pair is below an energy sum threshold.
+     * pair is below an energy sum threshold. This is defined
+     * as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2 <=
+     * PAIR_ENERGY_SUM_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -886,6 +977,7 @@
     /**
      * Checks if the sum of the energies of the clusters making up a
      * cluster pair is below the energy sum upper bound threshold.
+     * This is defined as <code>E_1 + E_2 <= PAIR_ENERGY_SUM_HIGH</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -897,6 +989,7 @@
     /**
      * Checks if the sum of the energies of the clusters making up a
      * cluster pair is above the energy sum lower bound threshold.
+     * This is defined as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2</code>.
      * @param clusterPair - The cluster pair to check.
      * @return Returns <code>true</code> if the cluster pair passes
      * the cut and <code>false</code> if it does not.
@@ -907,7 +1000,8 @@
     
     /**
      * Checks if the absolute difference between the times between
-     * two clusters is below the time coincidence cut.
+     * two clusters is below the time coincidence cut. This is defined
+     * as <code>|t_1 - t_2| <= PAIR_TIME_COINCIDENCE</code>.
      * @param clusterPair - The cluster pair to check.
      * @return <code>true</code> if the energy sum passes
      * the cut and <code>false</code> if it does not.
@@ -918,7 +1012,8 @@
     
     /**
      * Checks if the absolute difference between the times between
-     * two clusters is below the time coincidence cut.
+     * two clusters is below the time coincidence cut. This is defined
+     * as <code>|t_1 - t_2| <= PAIR_TIME_COINCIDENCE</code>.
      * @param clusterPair - The cluster pair to check.
      * @return <code>true</code> if the energy sum passes
      * the cut and <code>false</code> if it does not.
@@ -1018,9 +1113,8 @@
      * Gets the mapped position used by the SSP for a specific crystal.
      * @param ix - The crystal x-index.
      * @param iy - The crystal y-index.
-     * @return Returns the crystal position as a <double</code> array
-     * where the coordinates are ordered from the lowest to highest
-     * index as x, y, z.
+     * @return Returns the crystal position as a <code>double</code>
+     * array of form { x, y, z }.
      * @throws IndexOutOfBoundsException Occurs if in either of the
      * cases where <code>ix == 0</code> or <code>|ix| > 23</code> for
      * the x-index and either of the cases where <code>iy == 0</code>
@@ -1034,9 +1128,13 @@
 			throw new IndexOutOfBoundsException(String.format("Value \"%d\" is invalid for field y-index.", iy));
 		}
 		
-		// Return the mapped position.
-		if(ix < 1) { return position[5 - iy][22 - ix]; }
-		else { return position[5 - iy][23 - ix]; }
+		// Get the position map.
+		double posMap[];
+		if(ix < 1) { posMap = position[5 - iy][22 - ix]; }
+		else { posMap = position[5 - iy][23 - ix]; }
+		
+		// Return the corrected mapped position.
+		return new double[] { posMap[0], posMap[2], posMap[1] };
 	}
     
     /**
@@ -1047,11 +1145,11 @@
      * second clusters' y-positions.
      * @return Returns the cluster pair's coplanarity.
      */
-    private static double getValueCoplanarity(double[] x, double z[]) {
+    private static double getValueCoplanarity(double[] x, double y[]) {
         // Get the cluster angles.
         int[] clusterAngle = new int[2];
         for(int i = 0; i < 2; i++) {
-        	clusterAngle[i] = (int) Math.round(Math.atan(x[i] / z[i]) * 180.0 / Math.PI);
+        	clusterAngle[i] = (int) Math.round(Math.atan(x[i] / y[i]) * 180.0 / Math.PI);
         }
         
         // Calculate the coplanarity cut value.
@@ -1098,33 +1196,7 @@
      * energy slope equation E_low + R_min * F.
      * @return Returns the cut value.
      */
-    private static double getValueEnergySlope(double energy[], double x[], double z[], double energySlopeParamF) {
-    	// Determine which cluster is the lower-energy cluster.
-    	int lei = energy[0] < energy[1] ? 0 : 1;
-    	
-        // E + R*F
-        // Get the low energy cluster energy.
-        double slopeParamE = energy[lei];
-        
-        // Get the low energy cluster radial distance.
-        double slopeParamR = Math.sqrt((x[lei] * x[lei]) + (z[lei] * z[lei]));
-        
-        // Calculate the energy slope.
-        return slopeParamE + slopeParamR * energySlopeParamF;
-    }
-    
-    /**
-     * Calculates the value used by the energy slope cut. This version
-     * is superseded by the <code>getValueEnergySlope</code>, which
-     * more accurately mirrors the hardware behavior.
-     * @param clusterPair - The cluster pair from which the value should
-     * be calculated.
-     * @param energySlopeParamF - The value of the variable F in the
-     * energy slope equation E_low + R_min * F.
-     * @return Returns the cut value.
-     */
-    @Deprecated
-    private static double getValueEnergySlopeLegacy(double energy[], double x[], double y[], double energySlopeParamF) {
+    private static double getValueEnergySlope(double energy[], double x[], double y[], double energySlopeParamF) {
     	// Determine which cluster is the lower-energy cluster.
     	int lei = energy[0] < energy[1] ? 0 : 1;
     	
@@ -1140,6 +1212,32 @@
     }
     
     /**
+     * Calculates the value used by the energy slope cut. This version
+     * is superseded by the <code>getValueEnergySlope</code>, which
+     * more accurately mirrors the hardware behavior.
+     * @param clusterPair - The cluster pair from which the value should
+     * be calculated.
+     * @param energySlopeParamF - The value of the variable F in the
+     * energy slope equation E_low + R_min * F.
+     * @return Returns the cut value.
+     */
+    @Deprecated
+    private static double getValueEnergySlopeLegacy(double energy[], double x[], double y[], double energySlopeParamF) {
+    	// Determine which cluster is the lower-energy cluster.
+    	int lei = energy[0] < energy[1] ? 0 : 1;
+    	
+        // E + R*F
+        // Get the low energy cluster energy.
+        double slopeParamE = energy[lei];
+        
+        // Get the low energy cluster radial distance.
+        double slopeParamR = Math.sqrt((x[lei] * x[lei]) + (y[lei] * y[lei]));
+        
+        // Calculate the energy slope.
+        return slopeParamE + slopeParamR * energySlopeParamF;
+    }
+    
+    /**
      * Calculates the value used by the energy sum cut.
      * @param energy - A two-dimensional array consisting of the first
      * and second clusters' energies.
@@ -1242,7 +1340,10 @@
      * the hardware SSP position mappings for each crystal. Note that
      * ix in the array goes from -22 (representing ix = 23) up to 25
      * (representing ix = 23) and uses array index x = 0 as a valid
-     * parameter, while ix skips zero.
+     * parameter, while ix skips zero.<br/>
+     * <br/>
+     * Note that in this table, position[][] = { x, z, y } by in the
+     * coordinate system employed by the rest of the class.
      */
 	private static final double[][][] position = {
 		{	{ -340.003,   97.065,   87.845 }, { -324.283,   97.450,   87.875 }, { -308.648,   97.810,   87.900 },