Print

Print


Author: [log in to unmask]
Date: Thu Apr  2 10:05:53 2015
New Revision: 2656

Log:
Updated trigger diagnostic data storage tracking to be both more intuitive and also allow for tracking certain values more specifically.

Added:
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterEvent.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterMatchedPair.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterStatModule.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DetailedClusterEvent.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DiagnosticSnapshot.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/GeneralStatModule.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/RunDiagStats.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerDiagStats.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerEvent.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerStatModule.java
Modified:
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java
    java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java	Thu Apr  2 10:05:53 2015
@@ -7,7 +7,6 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -16,12 +15,12 @@
 import java.util.Map.Entry;
 import java.util.Set;
 
-import org.hps.analysis.trigger.event.ClusterMatchEvent;
-import org.hps.analysis.trigger.event.ClusterMatchStatus;
-import org.hps.analysis.trigger.event.ClusterMatchedPair;
-import org.hps.analysis.trigger.event.TriggerEfficiencyModule;
-import org.hps.analysis.trigger.event.TriggerMatchEvent;
-import org.hps.analysis.trigger.event.TriggerMatchStatus;
+import org.hps.analysis.trigger.data.ClusterMatchedPair;
+import org.hps.analysis.trigger.data.DetailedClusterEvent;
+import org.hps.analysis.trigger.data.DiagnosticSnapshot;
+import org.hps.analysis.trigger.data.RunDiagStats;
+import org.hps.analysis.trigger.data.TriggerDiagStats;
+import org.hps.analysis.trigger.data.TriggerEvent;
 import org.hps.analysis.trigger.event.TriggerPlotsModule;
 import org.hps.analysis.trigger.util.OutputLogger;
 import org.hps.analysis.trigger.util.Pair;
@@ -67,7 +66,8 @@
 	private List<List<SinglesTrigger<SSPCluster>>> sspSinglesTriggers = new ArrayList<List<SinglesTrigger<SSPCluster>>>(2);
 	
 	// Trigger modules for performing trigger analysis.
-	private int activeTrigger = -1;
+	//private int activeTrigger = -1;
+	private boolean[] tiFlags = new boolean[6];
 	private TriggerModule[] singlesTrigger = new TriggerModule[2];
 	private TriggerModule[] pairsTrigger = new TriggerModule[2];
 	private boolean[][] singlesCutsEnabled = new boolean[2][3];
@@ -82,27 +82,16 @@
 	private int hitAcceptance = 1;
 	private int noiseThreshold = 50;
 	private double energyAcceptance = 0.003;
-	private long localWindowStart = 0;
 	private boolean readDAQConfig = false;
-	private int localWindowThreshold = 10 * 1000;
+	private int localWindowThreshold = 1000000000;
 	private boolean performClusterVerification = true;
 	private boolean performSinglesTriggerVerification = true;
 	private boolean performPairTriggerVerification = true;
 	private boolean enforceTimeCompliance = false;
 	
 	// Efficiency tracking variables.
-	private ClusterMatchStatus clusterRunStats = new ClusterMatchStatus();
-	private ClusterMatchStatus clusterLocalStats = new ClusterMatchStatus();
-	private TriggerEfficiencyModule efficiencyRunStats = new TriggerEfficiencyModule();
-	private TriggerEfficiencyModule efficiencyLocalStats = new TriggerEfficiencyModule();
-	private TriggerMatchStatus[] triggerRunStats = { new TriggerMatchStatus(), new TriggerMatchStatus() };
-	private TriggerMatchStatus[] triggerLocalStats = { new TriggerMatchStatus(), new TriggerMatchStatus() };
-	
-	private int failedClusterEvents = 0;
-	private int failedSinglesEvents = 0;
-	private int failedPairEvents = 0;
-	private int totalEvents = 0;
-	private int noiseEvents = 0;
+	private RunDiagStats localStats = new RunDiagStats();
+	private RunDiagStats globalStats = new RunDiagStats();
     
     // Verbose settings.
     private boolean clusterFail = false;
@@ -356,146 +345,168 @@
 		System.out.println("======================================================================");
 		
 		// Print the general event failure rate.
-		int headSpaces = getPrintSpaces(totalEvents, triggerRunStats[0].getEventsOfTypeSeen(0), triggerRunStats[0].getEventsOfTypeSeen(1),
-				triggerRunStats[1].getEventsOfTypeSeen(0), triggerRunStats[1].getEventsOfTypeSeen(1));
+		int headSpaces = getPrintSpaces(globalStats.getEventCount());
 		System.out.println("General Event Statistics:");
 		System.out.printf("\tEvent Start Time      :: %.3f s%n", (startTime / Math.pow(10, 9)));
 		System.out.printf("\tEvent End Time        :: %.3f%n", (endTime / Math.pow(10, 9)));
 		System.out.printf("\tEvent Run Time        :: %.3f%n", ((endTime - startTime) / Math.pow(10, 9)));
 		System.out.printf("\tNoise Events          :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
-				noiseEvents, totalEvents, (100.0 * noiseEvents / totalEvents));
+				globalStats.getNoiseEvents(), globalStats.getEventCount(), (100.0 * globalStats.getNoiseEvents() / globalStats.getEventCount()));
 		System.out.printf("\tCluster Events Failed :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
-				failedClusterEvents, totalEvents, (100.0 * failedClusterEvents / totalEvents));
+				globalStats.getFailedClusterEventCount(), globalStats.getEventCount(), (100.0 * globalStats.getFailedClusterEventCount() / globalStats.getEventCount()));
 		System.out.printf("\tSingles Events Failed :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
-				failedSinglesEvents, totalEvents, (100.0 * failedSinglesEvents / totalEvents));
+				globalStats.getFailedSinglesEventCount(), globalStats.getEventCount(), (100.0 * globalStats.getFailedSinglesEventCount() / globalStats.getEventCount()));
 		System.out.printf("\tPair Events Failed    :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
-				failedPairEvents, totalEvents, (100.0 * failedPairEvents / totalEvents));
-		
-		// Print out how many events were triggered by a type along
-		// with how many were verified.
+				globalStats.getFailedPairEventCount(), globalStats.getEventCount(), (100.0 * globalStats.getFailedPairEventCount() / globalStats.getEventCount()));
+		
+		// Print out how many events reported a given TI type, both in
+		// total and hierarchically.
 		System.out.println();
 		System.out.println("Event Triggering Type Verification:");
-		System.out.printf("\tSingles Trigger 1     :: %" + headSpaces + "d / %" + headSpaces + "d",
-				triggerRunStats[0].getEventsOfTypeSeen(0), triggerRunStats[0].getEventsOfType(0));
-		if(triggerRunStats[0].getEventsOfType(0) != 0) {
-			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[0].getEventsOfTypeSeen(0) / triggerRunStats[0].getEventsOfType(0)));
-		} else { System.out.println(); }
-		System.out.printf("\tSingles Trigger 2     :: %" + headSpaces + "d / %" + headSpaces + "d",
-				triggerRunStats[0].getEventsOfTypeSeen(1), triggerRunStats[0].getEventsOfType(1));
-		if(triggerRunStats[0].getEventsOfType(0) != 0) {
-			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[0].getEventsOfTypeSeen(1) / triggerRunStats[0].getEventsOfType(1)));
-		} else { System.out.println(); }
-		System.out.printf("\tPair Trigger 1        :: %" + headSpaces + "d / %" + headSpaces + "d",
-				triggerRunStats[1].getEventsOfTypeSeen(0), triggerRunStats[0].getEventsOfType(0));
-		if(triggerRunStats[1].getEventsOfType(0) != 0) {
-			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[1].getEventsOfTypeSeen(0) / triggerRunStats[1].getEventsOfType(0)));
-		} else { System.out.println(); }
-		System.out.printf("\tPair Trigger 2        :: %" + headSpaces + "d / %" + headSpaces + "d",
-				triggerRunStats[1].getEventsOfTypeSeen(1), triggerRunStats[0].getEventsOfType(1));
-		if(triggerRunStats[1].getEventsOfType(0) != 0) {
-			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[1].getEventsOfTypeSeen(1) / triggerRunStats[1].getEventsOfType(1)));
-		} else { System.out.println(); }
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Trigger", "Total", "Hierarchical");
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Pulser", globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.PULSER, false),
+				globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.PULSER, true));
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Cosmic", globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.COSMIC, false),
+				globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.COSMIC, true));
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Singles 1", globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.SINGLES0, false),
+				globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.SINGLES0, true));
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Singles 2", globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.SINGLES1, false),
+				globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.SINGLES1, true));
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Pair 1", globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.PAIR0, false),
+				globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.PAIR0, true));
+		System.out.printf("\t%15s\t%15s\t%15s%n", "Pair 2", globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.PAIR1, false),
+				globalStats.getTriggerStats().getTITriggers(TriggerDiagStats.PAIR1, true));
 		
 		// Print the cluster verification data.
 		System.out.println();
 		System.out.println("Cluster Verification:");
-		System.out.printf("\tRecon Clusters        :: %d%n", clusterRunStats.getReconClusterCount());
-		System.out.printf("\tSSP Clusters          :: %d%n", clusterRunStats.getSSPClusterCount());
-		System.out.printf("\tClusters Matched      :: %d%n", clusterRunStats.getMatches());
-		System.out.printf("\tFailed (Position)     :: %d%n", clusterRunStats.getPositionFailures());
-		System.out.printf("\tFailed (Energy)       :: %d%n", clusterRunStats.getEnergyFailures());
-		System.out.printf("\tFailed (Hit Count)    :: %d%n", clusterRunStats.getHitCountFailures());
-		if(clusterRunStats.getReconClusterCount() == 0) { System.out.printf("\tCluster Efficiency    :: N/A%n"); }
-		else { System.out.printf("\tCluster Efficiency    :: %7.3f%%%n", 100.0 * clusterRunStats.getMatches() / clusterRunStats.getReconClusterCount()); }
+		System.out.printf("\tRecon Clusters        :: %d%n", globalStats.getClusterStats().getReconClusterCount());
+		System.out.printf("\tSSP Clusters          :: %d%n", globalStats.getClusterStats().getSSPClusterCount());
+		System.out.printf("\tClusters Matched      :: %d%n", globalStats.getClusterStats().getMatches());
+		System.out.printf("\tFailed (Position)     :: %d%n", globalStats.getClusterStats().getPositionFailures());
+		System.out.printf("\tFailed (Energy)       :: %d%n", globalStats.getClusterStats().getEnergyFailures());
+		System.out.printf("\tFailed (Hit Count)    :: %d%n", globalStats.getClusterStats().getHitCountFailures());
+		if(globalStats.getClusterStats().getReconClusterCount() == 0) {
+			System.out.printf("\tCluster Efficiency    :: N/A%n");
+		} else {
+			System.out.printf("\tCluster Efficiency    :: %7.3f%%%n",
+					100.0 * globalStats.getClusterStats().getMatches() / globalStats.getClusterStats().getReconClusterCount());
+		}
 		
 		// Print the trigger verification data.
 		for(int triggerType = 0; triggerType < 2; triggerType++) {
-			int spaces = getPrintSpaces(triggerRunStats[triggerType].getSSPSimTriggerCount(),
-					triggerRunStats[triggerType].getReconTriggerCount(), triggerRunStats[triggerType].getSSPBankTriggerCount(),
-					triggerRunStats[triggerType].getMatchedSSPTriggers(), triggerRunStats[triggerType].getMatchedReconTriggers());
+			// Get the trigger data. Type 0 represents singles triggers.
+			TriggerEvent[] triggerData = new TriggerEvent[2];
+			if(triggerType == 0) {
+				triggerData[0] = globalStats.getTriggerStats().getSingles0Stats();
+				triggerData[1] = globalStats.getTriggerStats().getSingles1Stats();
+			} else {
+				triggerData[0] = globalStats.getTriggerStats().getPair0Stats();
+				triggerData[1] = globalStats.getTriggerStats().getPair1Stats();
+			}
+			
+			// Get the basic trigger data.
+			int sspSimTriggers = triggerData[0].getSSPSimulatedTriggers() + triggerData[1].getSSPSimulatedTriggers();
+			int reconSimTriggers = triggerData[0].getReconSimulatedTriggers() + triggerData[1].getReconSimulatedTriggers();
+			int sspReportedTriggers = triggerData[0].getReportedTriggers() + triggerData[1].getReportedTriggers();
+			int sspMatchedTriggers = triggerData[0].getMatchedSSPSimulatedTriggers() + triggerData[1].getMatchedSSPSimulatedTriggers();
+			int reconMatchedTriggers = triggerData[0].getMatchedReconSimulatedTriggers() + triggerData[1].getMatchedReconSimulatedTriggers();
+			
+			// Print the basic trigger statistics.
+			int spaces = getPrintSpaces(sspSimTriggers, reconSimTriggers, sspReportedTriggers);
 			System.out.println();
 			if(triggerType == 0) { System.out.println("Singles Trigger Verification:"); }
 			else { System.out.println("Pair Trigger Verification:"); }
-			System.out.printf("\tSSP Cluster Sim Triggers   :: %" + spaces + "d%n", triggerRunStats[triggerType].getSSPSimTriggerCount());
-			System.out.printf("\tRecon Cluster Sim Triggers :: %" + spaces + "d%n", triggerRunStats[triggerType].getReconTriggerCount());
-			System.out.printf("\tSSP Reported Triggers      :: %" + spaces + "d%n", triggerRunStats[triggerType].getSSPBankTriggerCount());
-			System.out.printf("\tExtra Reported Triggers    :: %" + spaces + "d%n", triggerRunStats[triggerType].getExtraSSPBankTriggers());
-			
-			System.out.printf("\tInternal Efficiency        :: %" + spaces + "d / %" + spaces + "d ",
-					triggerRunStats[triggerType].getMatchedSSPTriggers(), triggerRunStats[triggerType].getSSPSimTriggerCount());
-			if(triggerRunStats[triggerType].getSSPSimTriggerCount() == 0) { System.out.printf("(N/A)%n"); }
-			else {
-				System.out.printf("(%7.3f%%)%n", (100.0 * triggerRunStats[triggerType].getMatchedSSPTriggers() / triggerRunStats[triggerType].getSSPSimTriggerCount()));
-			}
-			
-			System.out.printf("\tTrigger Efficiency         :: %" + spaces + "d / %" + spaces + "d ",
-					triggerRunStats[triggerType].getMatchedReconTriggers(), triggerRunStats[triggerType].getReconTriggerCount());
-			if(triggerRunStats[triggerType].getReconTriggerCount() == 0) { System.out.printf("(N/A)%n"); }
-			else { System.out.printf("(%7.3f%%)%n" , (100.0 * triggerRunStats[triggerType].getMatchedReconTriggers() / triggerRunStats[triggerType].getReconTriggerCount())); }
+			System.out.printf("\tSSP Cluster Sim Triggers   :: %" + spaces + "d%n", sspSimTriggers);
+			System.out.printf("\tRecon Cluster Sim Triggers :: %" + spaces + "d%n", reconSimTriggers);
+			System.out.printf("\tSSP Reported Triggers      :: %" + spaces + "d%n", sspReportedTriggers);
+			
+			System.out.printf("\tInternal Efficiency        :: %" + spaces + "d / %" + spaces + "d ", sspMatchedTriggers, sspSimTriggers);
+			if(sspSimTriggers == 0) { System.out.printf("(N/A)%n"); }
+			else { System.out.printf("(%7.3f%%)%n", (100.0 * sspMatchedTriggers / sspSimTriggers)); }
+			
+			System.out.printf("\tTrigger Efficiency         :: %" + spaces + "d / %" + spaces + "d ", reconMatchedTriggers, reconSimTriggers);
+			if(reconSimTriggers == 0) { System.out.printf("(N/A)%n"); }
+			else { System.out.printf("(%7.3f%%)%n" , (100.0 * reconMatchedTriggers / reconSimTriggers)); }
 			
 			// Print the individual cut performances.
 			if(triggerType == 0) {
-			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
-				int sspTriggerCount = triggerRunStats[0].getTotalSSPTriggers(triggerNum);
-				System.out.println();
-				System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
-				if(sspTriggerCount == 0) {
-					System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[0].getUnmatchedTriggers(triggerNum));
+				for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+					// Get the appropriate trigger statistics module.
+					TriggerEvent triggerStats;
+					if(triggerNum == 0) { triggerStats = globalStats.getTriggerStats().getSingles0Stats(); }
+					else { triggerStats = globalStats.getTriggerStats().getSingles1Stats(); }
+					
+					// Get the number of SSP triggers for this trigger number.
+					int sspTriggerCount = triggerStats.getSSPSimulatedTriggers();
+					//int sspTriggerCount = triggerRunStats[0].getTotalSSPTriggers(triggerNum);
+				
+					System.out.println();
+					System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
+					System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerStats.getUnmatchedSSPSimulatedTriggers());
+					//System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[0].getUnmatchedTriggers(triggerNum));
+					if(sspTriggerCount == 0) {
 						System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount);
+								triggerStats.getSSPCutFailures(ENERGY_MIN), sspTriggerCount);
 						System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount);
+								triggerStats.getSSPCutFailures(ENERGY_MAX), sspTriggerCount);
 						System.out.printf("\t\tCluster Hit Count          :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount);
+								triggerStats.getSSPCutFailures(HIT_COUNT), sspTriggerCount);
 					} else {
-						System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[0].getUnmatchedTriggers(triggerNum));
 						System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount,
-								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(ENERGY_MIN), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(ENERGY_MIN) / sspTriggerCount));
 						System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount,
-								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(ENERGY_MAX), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(ENERGY_MAX) / sspTriggerCount));
 						System.out.printf("\t\tCluster Hit Count          :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount,
-								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(HIT_COUNT), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(HIT_COUNT) / sspTriggerCount));
 					}
 				}
 			} else {
 				for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
-					int sspTriggerCount = triggerRunStats[1].getTotalSSPTriggers(triggerNum);
+					// Get the appropriate trigger statistics module.
+					TriggerEvent triggerStats;
+					if(triggerNum == 0) { triggerStats = globalStats.getTriggerStats().getPair0Stats(); }
+					else { triggerStats = globalStats.getTriggerStats().getPair1Stats(); }
+					
+					// Get the number of SSP triggers for this trigger number.
+					int sspTriggerCount = triggerStats.getSSPSimulatedTriggers();
+					
 					System.out.println();
 					System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
+					System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerStats.getUnmatchedSSPSimulatedTriggers());
 					if(sspTriggerCount == 0) {
-						System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[1].getUnmatchedTriggers(triggerNum));
 						System.out.printf("\t\tPair Energy Sum            :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount);
+								triggerStats.getSSPCutFailures(ENERGY_SUM), sspTriggerCount);
 						System.out.printf("\t\tPair Energy Difference     :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount);
+								triggerStats.getSSPCutFailures(ENERGY_DIFF), sspTriggerCount);
 						System.out.printf("\t\tPair Energy Slope          :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount);
+								triggerStats.getSSPCutFailures(ENERGY_SLOPE), sspTriggerCount);
 						System.out.printf("\t\tPair Coplanarity           :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), sspTriggerCount);
+								triggerStats.getSSPCutFailures(COPLANARITY), sspTriggerCount);
 					} else {
-						System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[1].getUnmatchedTriggers(triggerNum));
 						System.out.printf("\t\tPair Energy Sum            :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(ENERGY_SUM), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(ENERGY_SUM) / sspTriggerCount));
 						System.out.printf("\t\tPair Energy Difference     :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(ENERGY_DIFF), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(ENERGY_DIFF) / sspTriggerCount));
 						System.out.printf("\t\tPair Energy Slope          :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(ENERGY_SLOPE), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(ENERGY_SLOPE) / sspTriggerCount));
 						System.out.printf("\t\tPair Coplanarity           :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), sspTriggerCount,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY) / sspTriggerCount));
+								triggerStats.getSSPCutFailures(COPLANARITY), sspTriggerCount,
+								(100.0 * triggerStats.getSSPCutFailures(COPLANARITY) / sspTriggerCount));
 					}
 				}
 			}
 		}
 		
+		// Print out the trigger efficiency table.
 		System.out.println();
-		this.efficiencyRunStats.printModule();
+		globalStats.getTriggerStats().printEfficiencyTable();
 	}
 	
 	/**
@@ -516,7 +527,8 @@
 		}
 		
 		// Increment the total event count.
-		totalEvents++;
+		localStats.sawEvent(event.getTimeStamp());
+		globalStats.sawEvent(event.getTimeStamp());
 		
 		if(totalEvents%printResultsEveryNEvents == 0){
 			PrintResults();
@@ -582,7 +594,7 @@
 		// ==========================================================
 		
 		// Output the event number and information.
-		OutputLogger.printf("Event Number %d (%d)%n", totalEvents, event.getEventNumber());
+		OutputLogger.printf("Event Number %d (%d)%n", globalStats.getEventCount(), event.getEventNumber());
 		
 		// Get the SSP clusters.
 		if(event.hasCollection(GenericObject.class, bankCollectionName)) {
@@ -600,28 +612,40 @@
 				else if(AbstractIntData.getTag(obj) == TIData.BANK_TAG) {
 					tiBank = new TIData(obj);
 					
+					tiFlags = new boolean[6];
 					if(tiBank.isPulserTrigger()) {
 						OutputLogger.println("Trigger type :: Pulser");
-						activeTrigger = TriggerDiagnosticUtil.TRIGGER_PULSER;
+						tiFlags[TriggerDiagStats.PULSER] = true;
+						//activeTrigger = TriggerDiagnosticUtil.TRIGGER_PULSER;
 					} else if(tiBank.isSingle0Trigger()) {
 						OutputLogger.println("Trigger type :: Singles 1");
-						activeTrigger = TriggerDiagnosticUtil.TRIGGER_SINGLES_1;
+						tiFlags[TriggerDiagStats.SINGLES0] = true;
+						//activeTrigger = TriggerDiagnosticUtil.TRIGGER_SINGLES_1;
 					} else if(tiBank.isSingle1Trigger()) {
 						OutputLogger.println("Trigger type :: Singles 2");
-						activeTrigger = TriggerDiagnosticUtil.TRIGGER_SINGLES_2;
+						tiFlags[TriggerDiagStats.SINGLES1] = true;
+						//activeTrigger = TriggerDiagnosticUtil.TRIGGER_SINGLES_2;
 					} else if(tiBank.isPair0Trigger()) {
 						OutputLogger.println("Trigger type :: Pair 1");
-						activeTrigger = TriggerDiagnosticUtil.TRIGGER_PAIR_1;
+						tiFlags[TriggerDiagStats.PAIR0] = true;
+						//activeTrigger = TriggerDiagnosticUtil.TRIGGER_PAIR_1;
 					} else if(tiBank.isPair1Trigger()) {
 						OutputLogger.println("Trigger type :: Pair 2");
-						activeTrigger = TriggerDiagnosticUtil.TRIGGER_PAIR_2;
+						tiFlags[TriggerDiagStats.PAIR1] = true;
+						//activeTrigger = TriggerDiagnosticUtil.TRIGGER_PAIR_2;
 					} else if(tiBank.isCalibTrigger()) {
 						OutputLogger.println("Trigger type :: Cosmic");
-						activeTrigger = TriggerDiagnosticUtil.TRIGGER_COSMIC;
+						tiFlags[TriggerDiagStats.COSMIC] = true;
+						//activeTrigger = TriggerDiagnosticUtil.TRIGGER_COSMIC;
 					} else {
 						System.err.println("TriggerDiagnosticDriver: Skipping event; no TI trigger source found.");
 						return;
 					}
+					
+					// Pass the TI triggers to the run statistical data
+					// manager object.
+					localStats.getTriggerStats().sawTITriggers(tiFlags);
+					globalStats.getTriggerStats().sawTITriggers(tiFlags);
 				}
 			}
 			
@@ -669,7 +693,8 @@
 		if(event.hasCollection(CalorimeterHit.class, hitCollectionName)) {
 			// Check if there are more hits than the noise threshold.
 			if(event.get(CalorimeterHit.class, hitCollectionName).size() >= noiseThreshold) {
-				noiseEvents++;
+				localStats.sawNoiseEvent();
+				globalStats.sawNoiseEvent();
 				OutputLogger.println("Noise event detected. Skipping event...");
 				if(verbose) { OutputLogger.printLog(); }
 				return;
@@ -745,9 +770,16 @@
 		}
 		
 		// Track how many events failed due to each type of verification.
-		if(clusterFail) { failedClusterEvents++; }
-		if(pairInternalFail || pairEfficiencyFail) { failedPairEvents++; }
-		if(singlesInternalFail || singlesEfficiencyFail) { failedSinglesEvents++; }
+		if(clusterFail) {
+			localStats.failedClusterEvent();
+			globalStats.failedClusterEvent();
+		} if(pairInternalFail || pairEfficiencyFail) {
+			localStats.failedPairEvent();
+			globalStats.failedPairEvent();
+		} if(singlesInternalFail || singlesEfficiencyFail) {
+			localStats.failedSinglesEvent();
+			globalStats.failedSinglesEvent();
+		}
 		
 		
 		
@@ -768,25 +800,17 @@
 		// ==========================================================
 		// ==== Process Local Tracked Variables =====================
 		// ==========================================================
-		if(Calendar.getInstance().getTimeInMillis() - localWindowStart > localWindowThreshold) {
+		if(localStats.getDuration() > localWindowThreshold) {
 			// Write a snapshot of the driver to the event stream.
-			DiagSnapshot snapshot = new DiagSnapshot(clusterLocalStats, clusterRunStats,
-					triggerLocalStats[0], triggerRunStats[0], triggerLocalStats[1],
-					triggerRunStats[1], efficiencyRunStats, efficiencyLocalStats);
+			List<DiagnosticSnapshot> snapshotList = new ArrayList<DiagnosticSnapshot>(2);
+			snapshotList.add(localStats.getSnapshot());
+			snapshotList.add(globalStats.getSnapshot());
 			
 			// Push the snapshot to the data stream.
-			List<DiagSnapshot> snapshotCollection = new ArrayList<DiagSnapshot>(1);
-			snapshotCollection.add(snapshot);
-			event.put(diagnosticCollectionName, snapshotCollection);
+			event.put(diagnosticCollectionName, snapshotList);
 			
 			// Clear the local statistical data.
-			clusterLocalStats.clear();
-			triggerLocalStats[0].clear();
-			triggerLocalStats[1].clear();
-			efficiencyLocalStats.clear();
-			
-			// Update the last write time.
-			localWindowStart = Calendar.getInstance().getTimeInMillis();
+			localStats.clear();
 		}
 	}
 
@@ -884,7 +908,7 @@
 		
 		// Track the number of cluster pairs that were matched and that
 		// failed by failure type.
-		ClusterMatchEvent event = new ClusterMatchEvent();
+		DetailedClusterEvent event;
 		
 		if(enforceTimeCompliance) {
 			event = matchClustersTimeCompliant(reconClusters, sspClusters, energyAcceptance, hitAcceptance);
@@ -893,8 +917,12 @@
 		}
 		
 		// Add the event results to the global results.
-		clusterRunStats.addEvent(event, reconClusters, sspClusters);
-		clusterLocalStats.addEvent(event, reconClusters, sspClusters);
+		localStats.getClusterStats().addEvent(event);
+		globalStats.getClusterStats().addEvent(event);
+		localStats.getClusterStats().sawSSPClusters(sspClusters.size());
+		globalStats.getClusterStats().sawSSPClusters(sspClusters.size());
+		localStats.getClusterStats().sawReconClusters(reconClusters.size());
+		globalStats.getClusterStats().sawReconClusters(reconClusters.size());
 		
 		
 		
@@ -922,9 +950,9 @@
 		
 		// Print the matched clusters.
 		OutputLogger.println("Matched Clusters:");
-		if(event.getMatchedPairs().size() != 0) {
+		if(event.getMatches() != 0) {
 			// Iterate over the matched pairs.
-			for(ClusterMatchedPair pair : event.getMatchedPairs()) {
+			for(ClusterMatchedPair pair : event.getClusterPairs()) {
 				// If the pair is a match, print it out.
 				if(pair.isMatch()) {
 					OutputLogger.printf("\t%s --> %s%n",
@@ -971,7 +999,7 @@
 		}
 		
 		// Populate the matched and failed plots.
-		for(ClusterMatchedPair pair : event.getMatchedPairs()) {
+		for(ClusterMatchedPair pair : event.getClusterPairs()) {
 			 if(pair.getFirstElement() != null && pair.getSecondElement() != null) {
 				double energyDiff = pair.getSecondElement().getEnergy() - pair.getFirstElement().getEnergy();
 				int hitDiff = pair.getSecondElement().getHitCount() - pair.getFirstElement().getCalorimeterHits().size();
@@ -1029,11 +1057,11 @@
 	 * @return Returns the cluster matching results stored inside a
 	 * <code>clusterMatchEvent</code> object.
 	 */
-	private static final ClusterMatchEvent matchClusters(Collection<Cluster> reconClusters,
+	private static final DetailedClusterEvent matchClusters(Collection<Cluster> reconClusters,
 			Collection<SSPCluster> sspClusters, double energyWindow, int hitWindow) {
 		// Track the number of cluster pairs that were matched and that
 		// failed by failure type.
-		ClusterMatchEvent event = new ClusterMatchEvent();
+		DetailedClusterEvent event = new DetailedClusterEvent();
 		
 		// Create maps to link cluster position to the list of clusters
 		// that were found at that location.
@@ -1089,9 +1117,7 @@
 			// reason of position. The remainder of the loop may be
 			// skipped, since there is nothing to check.
 			if(sspList == null || sspList.isEmpty()) {
-				for(Cluster cluster : reconList) {
-					event.pairFailPosition(cluster, null);
-				}
+				event.pairFailPosition(reconList.size());
 				continue positionLoop;
 			}
 			
@@ -1104,7 +1130,7 @@
 			OutputLogger.printf("\tPermutations   :: %d%n", permutations.size());
 			
 			// Track the plotted values for the current best permutation.
-			ClusterMatchEvent bestPerm = null;
+			DetailedClusterEvent bestPerm = null;
 			
 			// Iterate over the permutations and find the permutation
 			// that produces the best possible result when compared to
@@ -1115,7 +1141,7 @@
 				permIndex++;
 				
 				// Track the plot values for this permutation.
-				ClusterMatchEvent perm = new ClusterMatchEvent();
+				DetailedClusterEvent perm = new DetailedClusterEvent();
 				
 				// Try to match each pair.
 				pairLoop:
@@ -1206,11 +1232,11 @@
 	 * @return Returns the cluster matching results stored inside a
 	 * <code>clusterMatchEvent</code> object.
 	 */
-	private static final ClusterMatchEvent matchClustersTimeCompliant(Collection<Cluster> reconClusters,
+	private static final DetailedClusterEvent matchClustersTimeCompliant(Collection<Cluster> reconClusters,
 			Collection<SSPCluster> sspClusters, double energyWindow, int hitWindow) {
 		// Track the number of cluster pairs that were matched and that
 		// failed by failure type.
-		ClusterMatchEvent event = new ClusterMatchEvent();
+		DetailedClusterEvent event = new DetailedClusterEvent();
 		
 		// Store the clusters which have been successfully paired.
 		Set<SSPCluster> sspMatched = new HashSet<SSPCluster>(sspClusters.size());
@@ -1375,7 +1401,7 @@
 		OutputLogger.println("======================================================================");
 		
 		// Track the number of triggers seen and the number found.
-		TriggerMatchEvent event = new TriggerMatchEvent();
+		TriggerEvent[] triggerEvent = { new TriggerEvent(), new TriggerEvent() };
 		
 		// ==========================================================
 		// ==== Output Event Summary ================================
@@ -1386,7 +1412,7 @@
 		if(isSingles) { sspTriggers = sspBank.getSinglesTriggers(); }
 		else { sspTriggers = sspBank.getPairTriggers(); }
 		
-		// Output the SSP cluster singles triggers.
+		// Output the SSP cluster triggers.
 		OutputLogger.println();
 		OutputLogger.println("SSP Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers");
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
@@ -1420,6 +1446,14 @@
 		}
 		if(sspTriggers.size() == 0) { OutputLogger.println("\tNone"); }
 		
+		// Update the trigger event with the counts for each type of
+		// simulated trigger. Reported triggers are counted later when
+		// already iterating over them.
+		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+			triggerEvent[triggerNum].sawSSPSimulatedTriggers(tiFlags, sspTriggerList.get(triggerNum).size());
+			triggerEvent[triggerNum].sawReconSimulatedTriggers(tiFlags, reconTriggerList.get(triggerNum).size());
+		}
+		
 		
 		
 		// ==========================================================
@@ -1447,6 +1481,9 @@
 			// Get the trigger information.
 			int triggerNum = sspTrigger.isFirstTrigger() ? 0 : 1;
 			OutputLogger.printf("\t%s%n", sspTrigger.toString());
+			
+			// Note that a bank trigger was seen.
+			triggerEvent[triggerNum].sawReportedTrigger();
 			
 			// Iterate over the SSP cluster simulated triggers and
 			// look for a trigger that matches.
@@ -1487,7 +1524,7 @@
 				// trigger number, than these triggers are a match.
 				sspTriggerSet.add(sspTrigger);
 				simTriggerSet.add(simTrigger);
-				event.matchedSSPPair(simTrigger, sspTrigger);
+				triggerEvent[triggerNum].matchedSSPTrigger(tiFlags);
 				OutputLogger.printf("[ %-15s ]%n", "success");
 				break matchLoop;
 			}
@@ -1578,13 +1615,13 @@
 				if(bestMatch == null) {
 					if(isSingles) { singlesInternalFail = true; }
 					else { pairInternalFail = true; }
-					event.matchedSSPPair(simTrigger, bestMatch, matchedCut);
+					triggerEvent[triggerNum].failedSSPTrigger();
 					OutputLogger.printf("\t\tTrigger %d :: %s :: %3.0f :: %s",
 							(triggerNum + 1), triggerPositionString(simTrigger),
 							getTriggerTime(simTrigger), simTrigger.toString());
 					OutputLogger.println(" --> No Valid Match Found");
 				} else {
-					event.matchedSSPPair(simTrigger, bestMatch, matchedCut);
+					triggerEvent[triggerNum].matchedSSPTrigger(tiFlags, matchedCut);
 					OutputLogger.printf("\t\tTrigger %d :: %s :: %3.0f :: %s",
 							(triggerNum + 1), triggerPositionString(simTrigger),
 							getTriggerTime(simTrigger), simTrigger.toString());
@@ -1607,22 +1644,6 @@
 		OutputLogger.println("Recon Cluster Trigger --> SSP Reported Trigger Match Status");
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 			for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) {
-				// If the trigger number and type align with the event
-				// trigger type, mark that it was seen.
-				if(triggerNum == 1) {
-					if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 && isSingles) {
-						event.setSawEventType(true);
-					} else if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_PAIR_1 && !isSingles) {
-						event.setSawEventType(true);
-					}
-				} else {
-					if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_SINGLES_2 && isSingles) {
-						event.setSawEventType(true);
-					} else if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_PAIR_2 && !isSingles) {
-						event.setSawEventType(true);
-					}
-				}
-				
 				OutputLogger.printf("\tTrigger %d :: %s :: %s%n", (triggerNum + 1),
 						triggerPositionString(simTrigger), simTrigger.toString());
 				
@@ -1664,7 +1685,7 @@
 					// If all the trigger flags match, then the
 					// triggers are a match.
 					sspTriggerSet.add(sspTrigger);
-					event.matchedReconPair(simTrigger, sspTrigger);
+					triggerEvent[triggerNum].matchedReconTrigger(tiFlags);
 					OutputLogger.print(" [ success         ]%n");
 					globalTriggerPlots.matchedTrigger(simTrigger);
 					matched = true;
@@ -1690,29 +1711,19 @@
 		// Print event statistics.
 		OutputLogger.println();
 		OutputLogger.println("Event Statistics:");
-		OutputLogger.printf("\tSaw Triggering Event Type  :: ");
-		if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_COSMIC || activeTrigger == TriggerDiagnosticUtil.TRIGGER_PULSER) {
-			OutputLogger.println("Unsupported for Cosmic/Pulser");
-		} else {
-			OutputLogger.println("" + event.sawEventType());
-		}
 		OutputLogger.printf("\tSSP Cluster Sim Triggers   :: %d%n", sspSimTriggers);
 		OutputLogger.printf("\tRecon Cluster Sim Triggers :: %d%n", reconSimTriggers);
 		OutputLogger.printf("\tSSP Reported Triggers      :: %d%n", sspTriggers.size());
-		if(sspSimTriggers == 0) {
-			OutputLogger.printf("\tInternal Efficiency        :: %d / %d (N/A)%n",
-					event.getMatchedSSPTriggers(), sspSimTriggers);
-		} else {
-			OutputLogger.printf("\tInternal Efficiency        :: %d / %d (%3.0f%%)%n",
-					event.getMatchedSSPTriggers(), sspSimTriggers, (100.0 * event.getMatchedSSPTriggers() / sspSimTriggers));
-		}
-		if(reconSimTriggers == 0) {
-			OutputLogger.printf("\tTrigger Efficiency         :: %d / %d (N/A)%n",
-					event.getMatchedReconTriggers(), reconSimTriggers);
-		} else {
-			OutputLogger.printf("\tTrigger Efficiency         :: %d / %d (%3.0f%%)%n",
-					event.getMatchedReconTriggers(), reconSimTriggers, (100.0 * event.getMatchedReconTriggers() / reconSimTriggers));
-		}
+		
+		int matchedSSPTriggers = triggerEvent[0].getMatchedSSPSimulatedTriggers() + triggerEvent[1].getMatchedSSPSimulatedTriggers();
+		OutputLogger.printf("\tInternal Efficiency        :: %d / %d ", matchedSSPTriggers, sspSimTriggers);
+		if(sspSimTriggers == 0) { OutputLogger.printf("(N/A)%n"); }
+		else { OutputLogger.printf("(%3.0f%%)%n", (100.0 * matchedSSPTriggers / sspSimTriggers)); }
+		
+		int matchedReconTriggers = triggerEvent[0].getMatchedReconSimulatedTriggers() + triggerEvent[1].getMatchedReconSimulatedTriggers();
+		OutputLogger.printf("\tTrigger Efficiency         :: %d / %d", matchedReconTriggers, reconSimTriggers);
+		if(reconSimTriggers == 0) { OutputLogger.printf("(N/A)%n"); }
+		else { OutputLogger.printf("(%3.0f%%)%n", (100.0 * matchedReconTriggers / reconSimTriggers)); }
 		
 		// Print the individual cut performances.
 		if(isSingles) {
@@ -1720,70 +1731,64 @@
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 				OutputLogger.printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
 				if(sspSimTriggers == 0) {
-					OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount[triggerNum]);
-					OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount[triggerNum]);
-					OutputLogger.printf("\tCluster Hit Count          :: %d / %d%n", event.getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(ENERGY_MIN), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(ENERGY_MAX), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tCluster Hit Count          :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(HIT_COUNT), sspTriggerCount[triggerNum]);
 				} else {
 					OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, ENERGY_MIN) / sspTriggerCount[triggerNum]));
+							triggerEvent[triggerNum].getSSPCutFailures(ENERGY_MIN), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(ENERGY_MIN) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, ENERGY_MAX) / sspTriggerCount[triggerNum]));
+							triggerEvent[triggerNum].getSSPCutFailures(ENERGY_MAX), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(ENERGY_MAX) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tCluster Hit Count          :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, HIT_COUNT) / sspTriggerCount[triggerNum]));
-				}
-				OutputLogger.printf("\tExcess Reported Triggers   :: %d%n", sspReportedExtras / 2);
+							triggerEvent[triggerNum].getSSPCutFailures(HIT_COUNT), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(HIT_COUNT) / sspTriggerCount[triggerNum]));
+				}
 			}
 			
 			// Update the global trigger tracking variables.
-			triggerRunStats[0].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
-			triggerLocalStats[0].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
-			efficiencyRunStats.addSinglesTriggers(activeTrigger, reconTriggerList);
-			efficiencyLocalStats.addSinglesTriggers(activeTrigger, reconTriggerList);
-			efficiencyRunStats.addEvent(activeTrigger, event);
-			efficiencyLocalStats.addEvent(activeTrigger, event);
+			localStats.getTriggerStats().getSingles0Stats().addEvent(triggerEvent[0]);
+			localStats.getTriggerStats().getSingles1Stats().addEvent(triggerEvent[1]);
+			globalStats.getTriggerStats().getSingles0Stats().addEvent(triggerEvent[0]);
+			globalStats.getTriggerStats().getSingles1Stats().addEvent(triggerEvent[1]);
 		} else {
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 				OutputLogger.println();
 				OutputLogger.printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
 				if(sspTriggerCount[triggerNum] == 0) {
-					OutputLogger.printf("\tPair Energy Sum            :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount[triggerNum]);
-					OutputLogger.printf("\tPair Energy Difference     :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount[triggerNum]);
-					OutputLogger.printf("\tPair Energy Slope          :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount[triggerNum]);
-					OutputLogger.printf("\tPair Coplanarity           :: %d / %d%n", event.getCutFailures(triggerNum, COPLANARITY), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Energy Sum            :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(ENERGY_SUM), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Energy Difference     :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(ENERGY_DIFF), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Energy Slope          :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(ENERGY_SLOPE), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Coplanarity           :: %d / %d%n", triggerEvent[triggerNum].getSSPCutFailures(COPLANARITY), sspTriggerCount[triggerNum]);
 				} else {
 					OutputLogger.printf("\tPair Energy Sum            :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, ENERGY_SUM) / sspTriggerCount[triggerNum]));
+							triggerEvent[triggerNum].getSSPCutFailures(ENERGY_SUM), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(ENERGY_SUM) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tPair Energy Difference     :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, ENERGY_DIFF) / sspTriggerCount[triggerNum]));
+							triggerEvent[triggerNum].getSSPCutFailures(ENERGY_DIFF), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(ENERGY_DIFF) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tPair Energy Slope          :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, ENERGY_SLOPE) / sspTriggerCount[triggerNum]));
+							triggerEvent[triggerNum].getSSPCutFailures(ENERGY_SLOPE), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(ENERGY_SLOPE) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tPair Coplanarity           :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, COPLANARITY), sspTriggerCount[triggerNum],
-							(100.0 * event.getCutFailures(triggerNum, COPLANARITY) / sspTriggerCount[triggerNum]));
-				}
-				OutputLogger.printf("\tExcess Reported Triggers   :: %d%n", sspReportedExtras / 2);
+							triggerEvent[triggerNum].getSSPCutFailures(COPLANARITY), sspTriggerCount[triggerNum],
+							(100.0 * triggerEvent[triggerNum].getSSPCutFailures(COPLANARITY) / sspTriggerCount[triggerNum]));
+				}
 			}
 			
 			// Update the global trigger tracking variables.
-			triggerRunStats[1].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
-			triggerLocalStats[1].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
-			efficiencyRunStats.addPairTriggers(activeTrigger, reconTriggerList);
-			efficiencyLocalStats.addSinglesTriggers(activeTrigger, reconTriggerList);
-			efficiencyRunStats.addEvent(activeTrigger, event);
-			efficiencyLocalStats.addEvent(activeTrigger, event);
+			localStats.getTriggerStats().getPair0Stats().addEvent(triggerEvent[0]);
+			localStats.getTriggerStats().getPair1Stats().addEvent(triggerEvent[1]);
+			globalStats.getTriggerStats().getPair0Stats().addEvent(triggerEvent[0]);
+			globalStats.getTriggerStats().getPair1Stats().addEvent(triggerEvent[1]);
 		}
 		
 		// Note whether the was a trigger match failure.
-		if(event.getMatchedReconTriggers() - reconSimTriggers != 0) {
+		if(triggerEvent[0].getFailedReconSimulatedTriggers() != 0 && triggerEvent[1].getFailedReconSimulatedTriggers() != 0) {
 			if(isSingles) { singlesEfficiencyFail = true; }
 			else { pairEfficiencyFail = true; }
-		} if(event.getMatchedSSPTriggers() - sspSimTriggers != 0) {
+		} if(triggerEvent[0].getFailedSSPSimulatedTriggers() != 0 && triggerEvent[1].getFailedSSPSimulatedTriggers() != 0) {
 			if(isSingles) { singlesInternalFail = true; }
 			else { pairInternalFail = true; }
 		}
@@ -2254,7 +2259,7 @@
 	 * @param secondEvent - The second cluster matching event.
 	 * @return Returns the cluster matching event that is better.
 	 */
-	private static final ClusterMatchEvent getBestPermutation(ClusterMatchEvent firstEvent, ClusterMatchEvent secondEvent) {
+	private static final DetailedClusterEvent getBestPermutation(DetailedClusterEvent firstEvent, DetailedClusterEvent secondEvent) {
 		// If both permutations are null, return that.
 		if(firstEvent == null && secondEvent == null) {
 			return null;

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterEvent.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterEvent.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterEvent.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,112 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>ClusterEvent</code> tracks reconstructed/SSP cluster
+ * pairs for the purpose of cluster matching. It maintains statistical
+ * information related to how many of each type of cluster was found
+ * as well as how many matched and failed with a given fail state.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class ClusterEvent extends ClusterStatModule {
+	/**
+	 * Fuses another <code>ClusterEvent</code> with this object. The
+	 * other event's cluster pairs and states will be added to those
+	 * already in this event.
+	 * @param event - The event to fuse.
+	 */
+	public void addEvent(ClusterEvent event) {
+		// If the event is null, do nothing.
+		if(event == null) { return; }
+		
+		// Add the values stored in the argument event to the counters
+		// in this event.
+		sspClusters   += event.sspClusters;
+		reconClusters += event.reconClusters;
+		matches       += event.matches;
+		failEnergy    += event.failEnergy;
+		failPosition  += event.failPosition;
+		failHitCount  += event.failHitCount;
+	}
+	
+	/**
+	 * Indicates whether at least one cluster pair in the event created
+	 * a fail state.
+	 * @return Returns <code>true</code> if not all clusters matched and
+	 * <code>false</code> otherwise.
+	 */
+	public boolean isFailState() {
+		return (failEnergy > 0) || (failHitCount > 0) || (failTime > 0) || (failPosition > 0);
+	}
+	
+	/**
+	 * Notes that a reconstructed cluster and SSP cluster pair failed
+	 * due to energy.
+	 */
+	public void pairFailEnergy() {
+		failEnergy++;
+	}
+	
+	/**
+	 * Notes that a reconstructed cluster and SSP cluster pair failed
+	 * due to hit count.
+	 */
+	public void pairFailHitCount() {
+		failHitCount++;
+	}
+	
+	/**
+	 * Notes that a reconstructed cluster and SSP cluster pair failed
+	 * due to position.
+	 */
+	public void pairFailPosition() {
+		failPosition++;
+	}
+	
+	/**
+	 * Notes that one or more reconstructed cluster and SSP cluster pair
+	 * failed due to position.
+	 * @param count - The number of events that failed in this manner.
+	 */
+	public void pairFailPosition(int count) {
+		// negative values are non-physical.
+		if(count < 0) {
+			throw new IllegalArgumentException("Cluster failure counts must be non-negative.");
+		}
+		
+		// Increment the count.
+		failPosition += count;
+	}
+	
+	/**
+	 * Notes that a reconstructed cluster and SSP cluster pair failed
+	 * due to time.
+	 */
+	public void pairFailTime() {
+		failTime++;
+	}
+	
+	/**
+	 * Notes that a reconstructed cluster and SSP cluster pair was
+	 * successfully matched.
+	 */
+	public void pairMatch() {
+		matches++;
+	}
+	
+	/**
+	 * Increments the number of reconstructed FADC clusters seen.
+	 * @param count - The number of clusters seen.
+	 */
+	public void sawReconClusters(int count) {
+		reconClusters += count;
+	}
+	
+	/**
+	 * Increments the number of SSP bank clusters seen.
+	 * @param count - The number of clusters seen.
+	 */
+	public void sawSSPClusters(int count) {
+		sspClusters += count;
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterMatchedPair.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterMatchedPair.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterMatchedPair.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,127 @@
+package org.hps.analysis.trigger.data;
+
+import org.hps.analysis.trigger.util.Pair;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
+import org.lcsim.event.Cluster;
+
+/**
+ * Class <code>ClusterMatchedPair</code> stores a reconstructed cluster
+ * and an SSP bank reported cluster which have been compared for the
+ * purpose of cluster matching. It also tracks what the match state of
+ * the two clusters is.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class ClusterMatchedPair extends Pair<Cluster, SSPCluster> {
+	// CLass variables.
+	private final byte state;
+	
+	/**
+	 * Instantiates a new <code>ClusterMatchedPair</code> object from
+	 * the two indicated clusters and marks their match state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 * @param state - The pair match state.
+	 */
+	public ClusterMatchedPair(Cluster reconCluster, SSPCluster sspCluster, byte state) {
+		// Set the cluster pairs.
+		super(reconCluster, sspCluster);
+		
+		// If the state is defined, set it. Otherwise, it is unknown.
+		if(state == TriggerDiagnosticUtil.CLUSTER_STATE_MATCHED
+				|| state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_POSITION
+				|| state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_ENERGY
+				|| state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_HIT_COUNT) {
+			this.state = state;
+		} else {
+			this.state = TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_UNKNOWN;
+		}
+	}
+	
+	/**
+	 * Gets the reconstructed cluster of the pair.
+	 * @return Returns the reconstructed cluster a <code>Cluster</cod>
+	 * object.
+	 */
+	public Cluster getReconstructedCluster() {
+		return getFirstElement();
+	}
+	
+	/**
+	 * Gets the SSP cluster of the pair.
+	 * @return Returns the SSP cluster as an <code>SSPCluster</code>
+	 * object.
+	 */
+	public SSPCluster getSSPCluster() {
+		return getSecondElement();
+	}
+	
+	/**
+	 * Gets the raw state identifier.
+	 * @return Returns the state identifier as a <code>byte</code>
+	 * primitive. Valid identifiers are defined in the class
+	 * <code>TriggerDiagnosticUtil</code>.
+	 */
+	public byte getState() {
+		return state;
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair failed to not being close
+	 * enough in energy.
+	 * @return Returns <code>true</code> if the pair match state is an
+	 * energy fail state and <code>false</code> otherwise.
+	 */
+	public boolean isEnergyFailState() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_ENERGY);
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair failed to match due to not
+	 * being close enough in hit count.
+	 * @return Returns <code>true</code> if the pair match state is a
+	 * hit count fail state and <code>false</code> otherwise.
+	 */
+	public boolean isHitCountFailState() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_HIT_COUNT);
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair matched.
+	 * @return Returns <code>true</code> if the pair match state is a
+	 * match state and <code>false</code> otherwise.
+	 */
+	public boolean isMatch() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_MATCHED);
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair failed to match due to the
+	 * cluster positions not aligning.
+	 * @return Returns <code>true</code> if the pair match state is a
+	 * position fail state and <code>false</code> otherwise.
+	 */
+	public boolean isPositionFailState() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_POSITION);
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair failed to match due to the
+	 * cluster time-stamps not aligning.
+	 * @return Returns <code>true</code> if the pair match state is a
+	 * time fail state and <code>false</code> otherwise.
+	 */
+	public boolean isTimeFailState() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_TIME);
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair has no known match state.
+	 * @return Returns <code>true</code> if the pair match state is
+	 * unknown and <code>false</code> otherwise.
+	 */
+	public boolean isUnknownState() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_UNKNOWN);
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterStatModule.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterStatModule.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/ClusterStatModule.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,124 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>ClusterStatModule</code> stores the statistical data
+ * for trigger diagnostic cluster matching.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class ClusterStatModule {
+	// Track cluster statistics.
+	protected int sspClusters   = 0;
+	protected int reconClusters = 0;
+	protected int matches       = 0;
+	protected int failEnergy    = 0;
+	protected int failPosition  = 0;
+	protected int failHitCount  = 0;
+	protected int failTime      = 0;
+	
+	/**
+	 * Instantiates a <code>ClusterStatModule</code> with no statistics
+	 * stored.
+	 */
+	ClusterStatModule() {  }
+	
+	/**
+	 * Clears all statistical information and resets the object of its
+	 * default, empty state.
+	 */
+	void clear() {
+		sspClusters   = 0;
+		reconClusters = 0;
+		matches       = 0;
+		failEnergy    = 0;
+		failPosition  = 0;
+		failHitCount  = 0;
+		failTime      = 0;
+	}
+	
+	@Override
+	public ClusterStatModule clone() {
+		// Create a clone.
+		ClusterStatModule clone = new ClusterStatModule();
+		
+		// Copy the statistical values to the clone.
+		clone.sspClusters   = sspClusters;
+		clone.reconClusters = reconClusters;
+		clone.matches       = matches;
+		clone.failEnergy    = failEnergy;
+		clone.failPosition  = failPosition;
+		clone.failHitCount  = failHitCount;
+		clone.failTime      = failTime;
+		
+		// Return the clone.
+		return clone;
+	}
+	
+	/**
+	 * Gets the number of cluster pairs stored in this event that are
+	 * marked with energy fail states.
+	 * @return Returns the number of instances of this state as an
+	 * <code>int</code> primitive.
+	 */
+	public int getEnergyFailures() {
+		return failEnergy;
+	}
+	
+	/**
+	 * Gets the number of cluster pairs stored in this event that are
+	 * marked with hit count fail states.
+	 * @return Returns the number of instances of this state as an
+	 * <code>int</code> primitive.
+	 */
+	public int getHitCountFailures() {
+		return failHitCount;
+	}
+	
+	/**
+	 * Gets the number of cluster pairs stored in this event that are
+	 * marked with position fail states.
+	 * @return Returns the number of instances of this state as an
+	 * <code>int</code> primitive.
+	 */
+	public int getMatches() {
+		return matches;
+	}
+	
+	/**
+	 * Gets the number of cluster pairs stored in this event that are
+	 * marked with position fail states.
+	 * @return Returns the number of instances of this state as an
+	 * <code>int</code> primitive.
+	 */
+	public int getPositionFailures() {
+		return failPosition;
+	}
+	
+	/**
+	 * Gets the total number of verifiable reconstructed clusters seen.
+     * @return Returns the cluster count as an <code>int</code>
+     * primitive.
+	 */
+    public int getReconClusterCount() {
+    	return reconClusters;
+    }
+    
+    /**
+     * Gets the total number of SSP bank clusters seen.
+     * @return Returns the cluster count as an <code>int</code>
+     * primitive.
+     */
+    public int getSSPClusterCount() {
+    	return sspClusters;
+    }
+	
+	/**
+	 * Gets the number of cluster pairs stored in this event that are
+	 * marked with time fail states.
+	 * @return Returns the number of instances of this state as an
+	 * <code>int</code> primitive.
+	 */
+	public int getTimeFailures() {
+		return failTime;
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DetailedClusterEvent.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DetailedClusterEvent.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DetailedClusterEvent.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,96 @@
+package org.hps.analysis.trigger.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
+import org.lcsim.event.Cluster;
+
+public class DetailedClusterEvent extends ClusterEvent {
+	// Store all of the pairs.
+	private List<ClusterMatchedPair> pairList = new ArrayList<ClusterMatchedPair>();
+	
+	/**
+	 * Fuses another <code>ClusterEvent</code> with this object. The
+	 * other event's cluster pairs and states will be added to those
+	 * already in this event.
+	 * @param event - The event to fuse.
+	 */
+	public void addEvent(ClusterEvent event) {
+		// Run the superclass method.
+		super.addEvent(event);
+		
+		// If the event is null, do nothing.
+		if(event == null) { return; }
+		
+		// Merge the list of cluster pairs, if applicable.
+		if(event instanceof DetailedClusterEvent) {
+			pairList.addAll(((DetailedClusterEvent) event).pairList);
+		}
+	}
+	
+	/**
+	 * Adds a reconstructed/SSP cluster pair and marks it as having an
+	 * energy fail state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 */
+	public void pairFailEnergy(Cluster reconCluster, SSPCluster sspCluster) {
+		pairFailEnergy();
+		pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_ENERGY));
+	}
+	
+	/**
+	 * Adds a reconstructed/SSP cluster pair and marks it as having a
+	 * hit count fail state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 */
+	public void pairFailHitCount(Cluster reconCluster, SSPCluster sspCluster) {
+		pairFailHitCount();
+		pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_HIT_COUNT));
+	}
+	
+	/**
+	 * Adds a reconstructed/SSP cluster pair and marks it as having a
+	 * position fail state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 */
+	public void pairFailPosition(Cluster reconCluster, SSPCluster sspCluster) {
+		pairFailPosition();
+		pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_POSITION));
+	}
+	
+	/**
+	 * Adds a reconstructed/SSP cluster pair and marks it as having a
+	 * time fail state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 */
+	public void pairFailTime(Cluster reconCluster, SSPCluster sspCluster) {
+		pairFailTime();
+		pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_TIME));
+	}
+	
+	/**
+	 * Adds a reconstructed/SSP cluster pair and marks it as having a
+	 * match state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 */
+	public void pairMatch(Cluster reconCluster, SSPCluster sspCluster) {
+		pairMatch();
+		pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_MATCHED));
+	}
+	
+	/**
+	 * Gets a list of all matched cluster pairs and their match states.
+	 * @return Returns the matched cluster pairs as a <code>List</code>
+	 * of <code>ClusterMatchedPair</code> objects.
+	 */
+	public List<ClusterMatchedPair> getClusterPairs() {
+		return pairList;
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DiagnosticSnapshot.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DiagnosticSnapshot.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/DiagnosticSnapshot.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,124 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>DiagnosticSnapshot</code> creates a snapshot of the
+ * trigger diagnostics at a specific time that can be passed to other
+ * classes. It is entirely static and will not change after creation.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class DiagnosticSnapshot {
+	// Store the TI trigger information.
+	private int[] tiSeenAll = new int[6];
+	private int[] tiSeenHierarchical = new int[6];
+	
+	// Store the statistical modules.
+	private final GeneralStatModule generalStats;
+	private final ClusterStatModule clusterStats;
+	private final TriggerStatModule[] triggerStats = new TriggerStatModule[4];
+	
+	/**
+	 * Creates a snapshot of the trigger diagnostic results.
+	 * @param stats - The run statistical object.
+	 */
+	DiagnosticSnapshot(RunDiagStats stats) {
+		// Store the statistical modules.
+		generalStats = stats.clone();
+		clusterStats = stats.getClusterStats().clone();
+		triggerStats[0] = stats.getTriggerStats().getSingles0Stats().clone();
+		triggerStats[1] = stats.getTriggerStats().getSingles1Stats().clone();
+		triggerStats[2] = stats.getTriggerStats().getPair0Stats().clone();
+		triggerStats[3] = stats.getTriggerStats().getPair1Stats().clone();
+		
+		// Copy the TI trigger data.
+		for(int triggerType = 0; triggerType < 6; triggerType++) {
+			tiSeenAll[triggerType] = stats.getTriggerStats().getTITriggers(triggerType, false);
+			tiSeenHierarchical[triggerType] = stats.getTriggerStats().getTITriggers(triggerType, true);
+		}
+	}
+	
+	/**
+	 * Gets the general run statistics.
+	 * @return Returns a <code>GeneralStatModule</code> object that
+	 * contains the statistics.
+	 */
+	public GeneralStatModule getGeneralStats() {
+		return generalStats;
+	}
+	
+	/**
+	 * Gets the cluster statistics.
+	 * @return Returns a <code>ClusterStatModule</code> object that
+	 * contains the statistics.
+	 */
+	public ClusterStatModule getClusterStats() {
+		return clusterStats;
+	}
+	
+	/**
+	 * Gets the singles 0 trigger statistics.
+	 * @return Returns a <code>TriggerStatModule</code> object that
+	 * contains the statistics.
+	 */
+	public TriggerStatModule getSingles0Stats() {
+		return triggerStats[0];
+	}
+	
+	/**
+	 * Gets the singles 1 trigger statistics.
+	 * @return Returns a <code>TriggerStatModule</code> object that
+	 * contains the statistics.
+	 */
+	public TriggerStatModule getSingles1Stats() {
+		return triggerStats[1];
+	}
+	
+	/**
+	 * Gets the pair 0 trigger statistics.
+	 * @return Returns a <code>TriggerStatModule</code> object that
+	 * contains the statistics.
+	 */
+	public TriggerStatModule getPair0Stats() {
+		return triggerStats[2];
+	}
+	
+	/**
+	 * Gets the pair 1 trigger statistics.
+	 * @return Returns a <code>TriggerStatModule</code> object that
+	 * contains the statistics.
+	 */
+	public TriggerStatModule getPair1Stats() {
+		return triggerStats[3];
+	}
+	
+	/**
+	 * Gets the total number of events where the TI reported a trigger
+	 * of the specified type.
+	 * @param triggerID - The identifier for the type of trigger.
+	 * @param unique - <code>true</code> returns only the number of
+	 * events where this trigger type was the <i>only</i> type seen by
+	 * the TI while <code>false</code> returns the number of events
+	 * that saw this trigger type without regards for other trigger
+	 * flags.
+	 * @return Returns the count as an <code>int</code>.
+	 */
+	public int getTITriggers(int triggerID, boolean hierarchical) {
+		// Verify the trigger type.
+		validateTriggerType(triggerID);
+		
+		// Increment the counters.
+		if(hierarchical) { return tiSeenHierarchical[triggerID]; }
+		else { return tiSeenAll[triggerID]; }
+	}
+	
+	/**
+	 * Produces an exception if the argument trigger type is not of a
+	 * supported type.
+	 * @param triggerType - The trigger type to verify.
+	 */
+	private static final void validateTriggerType(int triggerType) {
+		if(triggerType < 0 || triggerType > 5) {
+			throw new IndexOutOfBoundsException(String.format("Trigger type \"%d\" is not supported.", triggerType));
+		}
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/GeneralStatModule.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/GeneralStatModule.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/GeneralStatModule.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,103 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>GeneralStatModule</code> stores statistical data that
+ * is not specific to any one part of the diagnostics.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class GeneralStatModule {
+	// Store general run statistics.
+	protected long endTime = -1;
+	protected long startTime = -1;
+	protected int totalEvents = 0;
+	protected int noiseEvents = 0;
+	protected int failedPairEvents = 0;
+	protected int failedClusterEvents = 0;
+	protected int failedSinglesEvents = 0;
+	
+	/**
+	 * Clears all of the statistical counters in the object.
+	 */
+	void clear() {
+		endTime = -1;
+		startTime = -1;
+		totalEvents = 0;
+		noiseEvents = 0;
+		failedPairEvents = 0;
+		failedClusterEvents = 0;
+		failedSinglesEvents = 0;
+	}
+	
+	@Override
+	public GeneralStatModule clone() {
+		// Create the a cloned object.
+		GeneralStatModule clone = new GeneralStatModule();
+		
+		// Copy the tracked statistical data to the clone.
+		clone.endTime             = endTime;
+		clone.startTime           = startTime;
+		clone.totalEvents         = totalEvents;
+		clone.noiseEvents         = noiseEvents;
+		clone.failedPairEvents    = failedPairEvents;
+		clone.failedClusterEvents = failedClusterEvents;
+		clone.failedSinglesEvents = failedSinglesEvents;
+		
+		// Return the clone.
+		return clone;
+	}
+	
+	/**
+	 * Gets the length of time, in nanoseconds, over which the events
+	 * represented by this object occurred.
+	 * @return Returns the length of time as a <code>long</code>.
+	 */
+	public long getDuration() {
+		return endTime - startTime;
+	}
+	
+	/**
+	 * Gets the number of events seen.
+	 * @return Returns the number of events as an <code>int</code>.
+	 */
+	public int getEventCount() {
+		return totalEvents;
+	}
+	
+	/**
+	 * Gets the number of events in which at least one cluster was
+	 * not matched.
+	 * @return Returns the number of events as an <code>int</code>.
+	 */
+	public int getFailedClusterEventCount() {
+		return failedClusterEvents;
+	}
+	
+	/**
+	 * Gets the number of events in which at least one pair trigger
+	 * was not matched.
+	 * @return Returns the number of events as an <code>int</code>.
+	 */
+	public int getFailedPairEventCount() {
+		return failedPairEvents;
+	}
+
+	/**
+	 * Gets the number of events in which at least one singles trigger
+	 * was not matched.
+	 * @return Returns the number of events as an <code>int</code>.
+	 */
+	public int getFailedSinglesEventCount() {
+		return failedSinglesEvents;
+	}
+	
+	/**
+	 * Gets the number of events which were ignored due to having too
+	 * many hits in them.
+	 * @return Returns the number of events as an <code>int</code>.
+	 */
+	public int getNoiseEvents() {
+		return noiseEvents;
+	}
+
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/RunDiagStats.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/RunDiagStats.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/RunDiagStats.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,97 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>RunDiagStats</code> provides a central repository for
+ * all diagnostic statistics. It allows access and editing of each of
+ * the specific statistical modules and also is able to generate new
+ * diagnostic snapshots.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class RunDiagStats extends GeneralStatModule {
+	// Store the statistics for trigger matching.
+	private TriggerDiagStats triggerStats = new TriggerDiagStats();
+	
+	// Store the statistics for cluster matching.
+	private ClusterEvent clusterStats = new ClusterEvent();
+	
+	/**
+	 * Clears all of the statistical counters in the object.
+	 */
+	public void clear() {
+		super.clear();
+		clusterStats.clear();
+		triggerStats.clear();
+	}
+	
+	/**
+	 * Notes that an event failed to match all clusters.
+	 */
+	public void failedClusterEvent() {
+		failedClusterEvents++;
+	}
+	
+	/**
+	 * Notes that an event failed to match all pair triggers.
+	 */
+	public void failedPairEvent() {
+		failedPairEvents++;
+	}
+
+	/**
+	 * Notes that an event failed to match all singles triggers.
+	 */
+	public void failedSinglesEvent() {
+		failedSinglesEvents++;
+	}
+	
+	/**
+	 * Gets the cluster data.
+	 * @return Returns the <code>ClusterEvent</code> object that holds
+	 * the cluster data.
+	 */
+	public ClusterEvent getClusterStats() {
+		return clusterStats;
+	}
+	
+	/**
+	 * Gets a snapshot of the statistical data at the present time. The
+	 * snapshot will remain static and unchanged even if the generating
+	 * object itself is updated.
+	 * @return Returns a snapshot as a <code>DiagnosticSnapshot</code>
+	 * object.
+	 */
+	public DiagnosticSnapshot getSnapshot() {
+		return new DiagnosticSnapshot(this);
+	}
+	
+	/**
+	 * Gets the trigger data.
+	 * @return Returns the <code>TriggerDiagStats</code> object that holds
+	 * the cluster data.
+	 */
+	public TriggerDiagStats getTriggerStats() {
+		return triggerStats;
+	}
+	
+	/**
+	 * Notes that an event occurred.
+	 */
+	public void sawEvent(long eventTime) {
+		// Increment the event count.
+		totalEvents++;
+		
+		// If the start time is not defined, use this as the start time.
+		if(startTime == -1) { startTime = eventTime; }
+		
+		// The end time should always match the most recent event.
+		endTime = eventTime;
+	}
+
+	/**
+	 * Notes that an event was labeled as noise.
+	 */
+	public void sawNoiseEvent() {
+		noiseEvents++;
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerDiagStats.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerDiagStats.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerDiagStats.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,307 @@
+package org.hps.analysis.trigger.data;
+
+import org.hps.analysis.trigger.util.ComponentUtils;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+
+public class TriggerDiagStats {
+	// Define TI trigger type identifiers.
+	public static final int SINGLES0 = TriggerStatModule.SINGLES_0;
+	public static final int SINGLES1 = TriggerStatModule.SINGLES_1;
+	public static final int PAIR0    = TriggerStatModule.PAIR_0;
+	public static final int PAIR1    = TriggerStatModule.PAIR_1;
+	public static final int PULSER   = TriggerStatModule.PULSER;
+	public static final int COSMIC   = TriggerStatModule.COSMIC;
+	
+	// Tracks the number of TI triggers seen across all events for only
+	// the TI trigger with the highest priority in the event.
+	private int[] tiSeenHierarchical = new int[6];
+	
+	// Tracks the number of TI triggers across all events.
+	private int[] tiSeenAll = new int[6];
+	
+	// Store the statistics modules for each of the regular triggers.
+	private TriggerEvent[] triggerStats = new TriggerEvent[4];
+	
+	/**
+	 * Instantiates a new <code>TriggerDiagStats</code> object.
+	 */
+	public TriggerDiagStats() {
+		// Instantiate a trigger statistics module for each of the
+		// triggers for which statistics are supported.
+		for(int triggerType = 0; triggerType < 4; triggerType++) {
+			triggerStats[triggerType] = new TriggerEvent();
+		}
+	}
+	
+	/**
+	 * Clears all of the statistical counters in the object.
+	 */
+	void clear() {
+		// Clear the tracked TI trigger data.
+		for(int tiType = 0; tiType < 6; tiType++) {
+			tiSeenAll[tiType] = 0;
+			tiSeenHierarchical[tiType] = 0;
+		}
+		
+		// Clear the trigger statistical modules.
+		for(int triggerType = 0; triggerType < 4; triggerType++) {
+			triggerStats[triggerType].clear();
+		}
+	}
+	
+	/**
+	 * Gets the trigger data for the pair 0 trigger.
+	 * @return Returns the <code>TriggerEvent</code> object that holds
+	 * the trigger data for the pair 0 trigger.
+	 */
+	public TriggerEvent getPair0Stats() {
+		return triggerStats[PAIR0];
+	}
+	
+	/**
+	 * Gets the trigger data for the pair 1 trigger.
+	 * @return Returns the <code>TriggerEvent</code> object that holds
+	 * the trigger data for the pair 1 trigger.
+	 */
+	public TriggerEvent getPair1Stats() {
+		return triggerStats[PAIR1];
+	}
+	
+	/**
+	 * Gets the trigger data for the singles 0 trigger.
+	 * @return Returns the <code>TriggerEvent</code> object that holds
+	 * the trigger data for the singles 0 trigger.
+	 */
+	public TriggerEvent getSingles0Stats() {
+		return triggerStats[SINGLES0];
+	}
+	
+	/**
+	 * Gets the trigger data for the singles 1 trigger.
+	 * @return Returns the <code>TriggerEvent</code> object that holds
+	 * the trigger data for the singles 1 trigger.
+	 */
+	public TriggerEvent getSingles1Stats() {
+		return triggerStats[SINGLES1];
+	}
+	
+	/**
+	 * Gets the total number of events where the TI reported a trigger
+	 * of the specified type.
+	 * @param triggerID - The identifier for the type of trigger.
+	 * @param unique - <code>true</code> returns only the number of
+	 * events where this trigger type was the <i>only</i> type seen by
+	 * the TI while <code>false</code> returns the number of events
+	 * that saw this trigger type without regards for other trigger
+	 * flags.
+	 * @return Returns the count as an <code>int</code>.
+	 */
+	public int getTITriggers(int triggerID, boolean hierarchical) {
+		// Verify the trigger type.
+		validateTriggerType(triggerID);
+		
+		// Increment the counters.
+		if(hierarchical) { return tiSeenHierarchical[triggerID]; }
+		else { return tiSeenAll[triggerID]; }
+	}
+	
+	/**
+	 * Increments the counts tracking the number of TI flags seen.
+	 * @param flags - An array of <code>boolean</code> values of size
+	 * six. This represents one flag for each possible TI trigger type.
+	 */
+	public void sawTITriggers(boolean[] flags) {
+		// There must be six trigger flags and the array must not be
+		// null.
+		if(flags == null) {
+			throw new NullPointerException("TI trigger flags can not be null.");
+		} if(flags.length != 6) {
+			throw new IllegalArgumentException("TI trigger flags must be of size six.");
+		}
+		
+		// Check each TI flag in the order of the flag hierarchy. The
+		// first flag in the hierarchy that is true is recorded in the
+		// hierarchical count. All flags are recorded in the all count.
+		boolean foundHierarchical = false;
+		if(flags[PAIR1]) {
+			tiSeenAll[PAIR1]++;
+			if(!foundHierarchical) {
+				tiSeenHierarchical[PAIR1]++;
+				foundHierarchical = true;
+			}
+		} if(flags[PAIR0]) {
+			tiSeenAll[PAIR0]++;
+			if(!foundHierarchical) {
+				tiSeenHierarchical[PAIR0]++;
+				foundHierarchical = true;
+			}
+		} if(flags[SINGLES1]) {
+			tiSeenAll[SINGLES1]++;
+			if(!foundHierarchical) {
+				tiSeenHierarchical[SINGLES1]++;
+				foundHierarchical = true;
+			}
+		} if(flags[SINGLES0]) {
+			tiSeenAll[SINGLES0]++;
+			if(!foundHierarchical) {
+				tiSeenHierarchical[SINGLES0]++;
+				foundHierarchical = true;
+			}
+		} if(flags[PULSER]) {
+			tiSeenAll[PULSER]++;
+			if(!foundHierarchical) {
+				tiSeenHierarchical[PULSER]++;
+				foundHierarchical = true;
+			}
+		} if(flags[COSMIC]) {
+			tiSeenAll[COSMIC]++;
+			if(!foundHierarchical) {
+				tiSeenHierarchical[COSMIC]++;
+				foundHierarchical = true;
+			}
+		}
+	}
+	
+	/**
+	 * Prints the trigger statistics to the terminal as a table.
+	 */
+	public void printEfficiencyTable() {
+		// Get the trigger statistics tables.
+		int[][] seenStats = new int[6][4];
+		int[][] matchedStats = new int[6][4];
+		TriggerEvent[] triggerEvents = { getSingles0Stats(), getSingles1Stats(), getPair0Stats(), getPair1Stats() };
+		for(int i = 0; i < 4; i++) {
+			for(int j = 0; j < 6; j++) {
+				seenStats[j][i] = triggerEvents[i].getReconSimulatedTriggers(j);
+				matchedStats[j][i] = triggerEvents[i].getMatchedReconSimulatedTriggers(j);
+			}
+		}
+		
+		// Define constant spacing variables.
+		int columnSpacing = 3;
+		
+		// Define table headers.
+		String sourceName = "Source";
+		String seenName = "Trigger Efficiency";
+		
+		// Get the longest column header name.
+		int longestHeader = -1;
+		String[] headerNames = {
+				TriggerDiagnosticUtil.TRIGGER_NAME[0],
+				TriggerDiagnosticUtil.TRIGGER_NAME[1],
+				TriggerDiagnosticUtil.TRIGGER_NAME[2],
+				TriggerDiagnosticUtil.TRIGGER_NAME[3],
+				"TI Highest Type"
+		};
+		for(String triggerName : headerNames) {
+			longestHeader = ComponentUtils.max(longestHeader, triggerName.length());
+		}
+		longestHeader = ComponentUtils.max(longestHeader, sourceName.length());
+		
+		// Determine the spacing needed to display the largest numerical
+		// cell value.
+		int numWidth = -1;
+		int longestCell = -1;
+		for(int eventTriggerID = 0; eventTriggerID < 6; eventTriggerID++) {
+			for(int seenTriggerID = 0; seenTriggerID < 4; seenTriggerID++) {
+				int valueSize = ComponentUtils.getDigits(seenStats[eventTriggerID][seenTriggerID]);
+				int cellSize = valueSize * 2 + 13;
+				if(cellSize > longestCell) {
+					longestCell = cellSize;
+					numWidth = valueSize;
+				}
+			}
+		}
+		
+		// The total column width can then be calculated from the
+		// longer of the header and cell values.
+		int columnWidth = ComponentUtils.max(longestCell, longestHeader);
+		int sourceWidth = ComponentUtils.max(
+				TriggerDiagnosticUtil.TRIGGER_NAME[0].length(), TriggerDiagnosticUtil.TRIGGER_NAME[1].length(),
+				TriggerDiagnosticUtil.TRIGGER_NAME[2].length(), TriggerDiagnosticUtil.TRIGGER_NAME[3].length(),
+				TriggerDiagnosticUtil.TRIGGER_NAME[4].length(), TriggerDiagnosticUtil.TRIGGER_NAME[5].length(),
+				sourceName.length() );
+		
+		// Calculate the total width of the table value header columns.
+		int headerTotalWidth = (headerNames.length * columnWidth)
+				+ ((headerNames.length - 1) * columnSpacing);
+		
+		// Write the table header.
+		String spacingText = ComponentUtils.getChars(' ', columnSpacing);
+		System.out.println(ComponentUtils.getChars(' ', sourceWidth) + spacingText
+				+ getCenteredString(seenName, headerTotalWidth));
+		
+		// Create the format strings for the cell values.
+		String headerFormat = "%-" + sourceWidth + "s" + spacingText;
+		String cellFormat = "%" + numWidth + "d / %" + numWidth + "d (%7.3f)";
+		String nullText = getCenteredString(ComponentUtils.getChars('-', numWidth) + " / "
+				+ ComponentUtils.getChars('-', numWidth) + " (  N/A  )", columnWidth) + spacingText;
+		
+		// Print the column headers.
+		System.out.printf(headerFormat, sourceName);
+		for(String header : headerNames) {
+			System.out.print(getCenteredString(header, columnWidth) + spacingText);
+		}
+		System.out.println();
+		
+		// Write out the value columns.
+		for(int eventTriggerID = 0; eventTriggerID < 6; eventTriggerID++) {
+			// Print out the row header.
+			System.out.printf(headerFormat, TriggerDiagnosticUtil.TRIGGER_NAME[eventTriggerID]);
+			
+			// Print the cell values.
+			for(int seenTriggerID = 0; seenTriggerID < 4; seenTriggerID++) {
+				if(seenTriggerID == eventTriggerID) { System.out.print(nullText); }
+				else {
+					String cellText = String.format(cellFormat, matchedStats[eventTriggerID][seenTriggerID],
+							seenStats[eventTriggerID][seenTriggerID],
+							(100.0 * matchedStats[eventTriggerID][seenTriggerID] / seenStats[eventTriggerID][seenTriggerID]));
+					System.out.print(getCenteredString(cellText, columnWidth) + spacingText);
+				}
+			}
+			
+			// Output the number of events that had only the trigger
+			// type ID for the current trigger type flagged by the TI.
+			System.out.print(getCenteredString("" + getTITriggers(eventTriggerID, true), columnWidth) + spacingText);
+			
+			// Start a new line.
+			System.out.println();
+		}
+	}
+	
+	/**
+	 * Produces a <code>String</code> of the indicated length with the
+	 * text <code>value</code> centered in the middle. Extra length is
+	 * filled through spaces before and after the text.
+	 * @param value - The text to display.
+	 * @param width - The number of spaces to include.
+	 * @return Returns a <code>String</code> of the specified length,
+	 * or the argument text if it is longer.
+	 */
+	private static final String getCenteredString(String value, int width) {
+		// The method can not perform as intended if the argument text
+		// exceeds the requested string length. Just return the text.
+		if(width <= value.length()) {
+			return value;
+		}
+		
+		// Otherwise, get the amount of buffering needed to center the
+		// text and add it around the text to produce the string.
+		else {
+			int buffer = (width - value.length()) / 2;
+			return ComponentUtils.getChars(' ', buffer) + value
+					+ ComponentUtils.getChars(' ', width - buffer - value.length());
+		}
+	}
+	
+	/**
+	 * Produces an exception if the argument trigger type is not of a
+	 * supported type.
+	 * @param triggerType - The trigger type to verify.
+	 */
+	private static final void validateTriggerType(int triggerType) {
+		if(triggerType < 0 || triggerType > 5) {
+			throw new IndexOutOfBoundsException(String.format("Trigger type \"%d\" is not supported.", triggerType));
+		}
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerEvent.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerEvent.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerEvent.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,271 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>TriggerEvent</code> tracks all of the statistics from
+ * a single trigger event. It is an extension of the statistics class
+ * <code>TriggerStatModule</code> which implements methods for altering
+ * the values in the base class.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerEvent extends TriggerStatModule {
+	/**
+	 * Adds the statistics from one event object into this one.
+	 * @param event - The event data to add.
+	 */
+	public void addEvent(TriggerStatModule event) {
+		// Merge the values that do not depend on trigger source type.
+		reportedTriggers += event.reportedTriggers;
+		
+		// Merge each value that depends on the trigger source type.
+		for(int sourceType = 0; sourceType < 2; sourceType++) {
+			simTriggers[sourceType] += event.simTriggers[sourceType];
+			matchedTriggers[sourceType] += event.matchedTriggers[sourceType];
+			unmatchedTriggers[sourceType] += event.unmatchedTriggers[sourceType];
+			
+			// Merge the number of times each cut failed.
+			for(int cutID = 0; cutID < 4; cutID++) {
+				failedCuts[sourceType][cutID] += event.failedCuts[sourceType][cutID];
+			}
+			
+			// Copy the values for the TI flag trigger counters.
+			for(int tiType = 0; tiType < 6; tiType++) {
+				tiTriggersSeen[sourceType][tiType] += event.tiTriggersSeen[sourceType][tiType];
+				tiTriggersMatched[sourceType][tiType] += event.tiTriggersMatched[sourceType][tiType];
+			}
+		}
+	}
+	
+	/**
+	 * Indicates that a reconstructed trigger could not be matched, even
+	 * partially, to an SSP bank trigger.
+	 */
+	public void failedReconTrigger() {
+		unmatchedTriggers[RECON]++;
+	}
+	
+	/**
+	 * Indicates that an SSP simulated trigger could not be matched, even
+	 * partially, to an SSP bank trigger.
+	 */
+	public void failedSSPTrigger() {
+		unmatchedTriggers[SSP]++;
+	}
+
+	/**
+	 * Indicates that a trigger simulated from a reconstructed cluster
+	 * was successfully matched to a trigger in the SSP bank.
+	 * @param tiFlags - An array of size 6 indicating which TI bank
+	 * flags are active and which are not.
+	 * @param triggerTypeID - An identifier indicating the type of
+	 * trigger that was matched.
+	 */
+	public void matchedReconTrigger(boolean[] tiFlags) {
+		matchedTriggers(tiFlags, RECON);
+	}
+	
+	/**
+	 * Indicates that a trigger simulated from a reconstructed cluster
+	 * was partially matched to a trigger in the SSP bank, and notes
+	 * which cuts did and did not match.
+	 * @param tiFlags - An array of size 6 indicating which TI bank
+	 * flags are active and which are not.
+	 * @param triggerTypeID - An identifier indicating the type of
+	 * trigger that was matched.
+	 * @param matchedCuts - An array of size 3 or 4 indicating which
+	 * cuts did and did not align between the triggers.
+	 */
+	public void matchedReconTrigger(boolean[] tiFlags, boolean[] matchedCuts) {
+		matchedTriggers(tiFlags, matchedCuts, RECON);
+	}
+	
+	/**
+	 * Indicates that a trigger simulated from an SSP bank cluster was
+	 * successfully matched to a trigger in the SSP bank.
+	 * @param tiFlags - An array of size 6 indicating which TI bank
+	 * flags are active and which are not.
+	 * @param triggerTypeID - An identifier indicating the type of
+	 * trigger that was matched.
+	 */
+	public void matchedSSPTrigger(boolean[] tiFlags) {
+		matchedTriggers(tiFlags, SSP);
+	}
+	
+	/**
+	 * Indicates that a trigger simulated from an SSP bank cluster was
+	 * partially matched to a trigger in the SSP bank, and notes which
+	 * cuts did and did not match.
+	 * @param tiFlags - An array of size 6 indicating which TI bank
+	 * flags are active and which are not.
+	 * @param triggerTypeID - An identifier indicating the type of
+	 * trigger that was matched.
+	 * @param matchedCuts - An array of size 3 or 4 indicating which
+	 * cuts did and did not align between the triggers.
+	 */
+	public void matchedSSPTrigger(boolean[] tiFlags, boolean[] matchedCuts) {
+		matchedTriggers(tiFlags, matchedCuts, SSP);
+	}
+	
+	/**
+	 * Indicates that a trigger simulated from a reconstructed cluster
+	 * was seen and increments the count for this type of trigger by one.
+	 * @param tiFlags - Whether or not each of the TI bank flags is
+	 * active or not.
+	 */
+	public void sawReconSimulatedTrigger(boolean[] tiFlags) {
+		sawReconSimulatedTriggers(tiFlags, 1);
+	}
+	
+	/**
+	 * Indicates that a number triggers simulated from reconstructed
+	 * clusters were seen and increments the count for this type of
+	 * trigger by the indicated number.
+	 * @param tiFlags - Whether or not each of the TI bank flags is
+	 * active or not.
+	 * @param count - The number of simulated triggers seen.
+	 */
+	public void sawReconSimulatedTriggers(boolean[] tiFlags, int count) {
+		// Increment the total count.
+		simTriggers[RECON] += count;
+		
+		// Increment the TI flag counters.
+		for(int tiType = 0; tiType < 6; tiType++) {
+			if(tiFlags[tiType]) {
+				tiTriggersSeen[RECON][tiType] += count;
+			}
+		}
+	}
+	
+	/**
+	 * Indicates that a trigger from the SSP trigger bank was seen and
+	 * increments the count for this type of trigger by one.
+	 */
+	public void sawReportedTrigger() {
+		sawReportedTriggers(1);
+	}
+	
+	/**
+	 * Indicates that a number triggers from the SSP trigger bank were
+	 * seen and increments the count for this type of trigger by the
+	 * indicated number.
+	 * @param count - The number of simulated triggers seen.
+	 */
+	public void sawReportedTriggers(int count) {
+		reportedTriggers += count;
+	}
+	
+	/**
+	 * Indicates that a trigger simulated from an SSP bank cluster was
+	 * seen and increments the count for this type of trigger by one.
+	 * @param tiFlags - Whether or not each of the TI bank flags is
+	 * active or not.
+	 */
+	public void sawSSPSimulatedTrigger(boolean[] tiFlags) {
+		sawSSPSimulatedTriggers(tiFlags, 1);
+	}
+	
+	/**
+	 * Indicates that a number triggers simulated from SSP bank clusters
+	 * were seen and increments the count for this type of trigger by
+	 * the indicated number.
+	 * @param tiFlags - Whether or not each of the TI bank flags is
+	 * active or not.
+	 * @param count - The number of simulated triggers seen.
+	 */
+	public void sawSSPSimulatedTriggers(boolean[] tiFlags, int count) {
+		// Increment the total count.
+		simTriggers[SSP] += count;
+		
+		// Increment the TI flag counters.
+		for(int tiType = 0; tiType < 6; tiType++) {
+			if(tiFlags[tiType]) {
+				tiTriggersSeen[SSP][tiType] += count;
+			}
+		}
+	}
+	
+	/**
+	 * Indicates that a simulated trigger was successfully matched to
+	 * an SSP bank trigger.
+	 * @param tiFlags - An array of size 6 indicating which TI bank
+	 * flags are active and which are not.
+	 * @param sourceType - Uses <code>SSP</code> for triggers simulated
+	 * from an SSP bank cluster and <code>RECON</code> for triggers that
+	 * were simulated from a reconstructed cluster.
+	 */
+	private final void matchedTriggers(boolean[] tiFlags, int sourceType) {
+		// Increment the total triggers matched.
+		matchedTriggers[sourceType]++;
+		
+		// Increment the triggers matched for this type for each if
+		// the active TI bank flags.
+		for(int tiType = 0; tiType < 6; tiType++) {
+			if(tiFlags[tiType]) {
+				tiTriggersMatched[sourceType][tiType]++;
+			}
+		}
+	}
+	
+	/**
+	 * Indicates that a simulated trigger was partially matched to a
+	 * trigger in the SSP bank, and notes which cuts did and did not
+	 * match.
+	 * @param tiFlags - An array of size 6 indicating which TI bank
+	 * flags are active and which are not.
+	 * @param sourceType - Uses <code>SSP</code> for triggers simulated
+	 * from an SSP bank cluster and <code>RECON</code> for triggers that
+	 * were simulated from a reconstructed cluster.
+	 */
+	private void matchedTriggers(boolean[] tiFlags, boolean[] matchedCuts, int sourceType) {
+		// The matched cuts must be defined.
+		if(matchedCuts == null) {
+			throw new NullPointerException("The matched cuts array must be defined.");
+		}
+		
+		// The matched cuts array must be of either size 3 or 4.
+		if(matchedCuts.length != 3 && matchedCuts.length != 4) {
+			throw new IllegalArgumentException("All triggers must use either three or four cuts.");
+		}
+		
+		// Increment the counters for each cut that was no matched. Also
+		// track whether or not a cut actually failed.
+		boolean cutFailed = false;
+		for(int cutIndex = 0; cutIndex < matchedCuts.length; cutIndex++) {
+			if(!matchedCuts[cutIndex]) {
+				failedCuts[sourceType][cutIndex]++;
+				cutFailed = true;
+			}
+		}
+		
+		// If no cut failed, this is actually a match. Increment the
+		// appropriate counters.
+		if(!cutFailed) {
+			matchedTriggers(tiFlags, sourceType);
+		}
+	}
+	
+	@Deprecated
+	public String getPrintData() {
+		StringBuffer out = new StringBuffer();
+
+		out.append("\n");
+		out.append("Trigger Result\n");
+		out.append("SSP Sim Triggers    :: " + simTriggers[SSP] + "\n");
+		out.append("Recon Sim Triggers  :: " + simTriggers[RECON] + "\n");
+		out.append("Reported Triggers   :: " + reportedTriggers + "\n");
+		out.append(String.format("Internal Efficiency :: %d / %d (%7.3f)%n", matchedTriggers[SSP], simTriggers[SSP],
+				(100.0 * matchedTriggers[SSP] / simTriggers[SSP])));
+		out.append(String.format("Trigger Efficiency  :: %d / %d (%7.3f)%n", matchedTriggers[RECON], simTriggers[RECON],
+				(100.0 * matchedTriggers[RECON] / simTriggers[RECON])));
+		
+		out.append("\n");
+		out.append("Individual Cut Failure Rates\n");
+		out.append("Unmatched Triggers   :: " + unmatchedTriggers[SSP] + "\n");
+		for(int i = 0; i < 4; i++) {
+			out.append(String.format("\tCut %d :: %d / %d (%7.3f)%n", i, failedCuts[SSP][i], simTriggers[SSP],
+					(100.0 * failedCuts[SSP][i] / simTriggers[SSP])));
+		}
+		
+		return out.toString();
+	}
+}

Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerStatModule.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerStatModule.java	(added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/data/TriggerStatModule.java	Thu Apr  2 10:05:53 2015
@@ -0,0 +1,294 @@
+package org.hps.analysis.trigger.data;
+
+/**
+ * Class <code>TriggerStatModule</code> holds all the statistics from
+ * a single trigger event. The variables in this class are set by the
+ * extending class <code>TriggerEvent</code>, while this object lacks
+ * any external means to alter its values so that it can be used in a
+ * static fashion.
+ * 
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerStatModule {
+	// Store the reference index for SSP simulated triggers and recon
+	// simulated triggers.
+	protected static final int SSP = 0;
+	protected static final int RECON = 1;
+	
+	// Define TI trigger type identifiers.
+	public static final int SINGLES_0 = 0;
+	public static final int SINGLES_1 = 1;
+	public static final int PAIR_0    = 2;
+	public static final int PAIR_1    = 3;
+	public static final int PULSER    = 4;
+	public static final int COSMIC    = 5;
+	
+	// Track the number of simulated triggers seen for each source type.
+	// SSP simulated triggers from the SSP bank clusters. Reconstructed
+	// simulated triggers come from clusters built from FADC data.
+	protected int[] simTriggers = new int[2];
+	
+	// Also track the number of triggers reported by the SSP bank.
+	protected int reportedTriggers = 0;
+	
+	// Track the number of simulated triggers of each type that were
+	// successfully matched.
+	protected int[] matchedTriggers = new int[2];
+	
+	// Track the number of simulated triggers that could not be matched
+	// at all.
+	protected int[] unmatchedTriggers = new int[2];
+	
+	// Track which cuts succeeded and which cuts failed for each type.
+	// Note that this is currently only tracked for SSP cluster triggers.
+	protected int[][] failedCuts = new int[2][4];
+	
+	// Store the number of trigger matches seen over all events that
+	// contain a given TI flag.
+	protected int[][] tiTriggersSeen = new int[2][6];
+	protected int[][] tiTriggersMatched = new int[2][6];
+	
+	/**
+	 * Clears all of the statistical counters in the object.
+	 */
+	void clear() {
+		// Clear all values.
+		for(int sourceType = 0; sourceType < 2; sourceType++) {
+			// Clear the general statistics.
+			simTriggers[sourceType]       = 0;
+			matchedTriggers[sourceType]   = 0;
+			unmatchedTriggers[sourceType] = 0;
+			
+			// Clear the cut failure statistics.
+			for(int cutID = 0; cutID < 4; cutID++) {
+				failedCuts[sourceType][cutID] = 0;
+			}
+			
+			// Clear the TI flag statistics.
+			for(int tiType = 0; tiType < 6; tiType++) {
+				tiTriggersSeen[sourceType][tiType]    = 0;
+				tiTriggersMatched[sourceType][tiType] = 0;
+			}
+		}
+	}
+	
+	@Override
+	public TriggerStatModule clone() {
+		// Make a new statistics module.
+		TriggerStatModule clone = new TriggerStatModule();
+		
+		// Copy the values that do not depend on trigger source type.
+		clone.reportedTriggers = reportedTriggers;
+		
+		// Set each value that depends on the trigger source type.
+		for(int sourceType = 0; sourceType < 2; sourceType++) {
+			clone.simTriggers[sourceType] = simTriggers[sourceType];
+			clone.matchedTriggers[sourceType] = matchedTriggers[sourceType];
+			clone.unmatchedTriggers[sourceType] = unmatchedTriggers[sourceType];
+			
+			// Set the number of times each cut failed.
+			for(int cutID = 0; cutID < 4; cutID++) {
+				clone.failedCuts[sourceType][cutID] = failedCuts[sourceType][cutID];
+			}
+			
+			// Copy the values for the TI flag trigger counters.
+			for(int tiType = 0; tiType < 6; tiType++) {
+				clone.tiTriggersSeen[sourceType][tiType] = tiTriggersSeen[sourceType][tiType];
+				clone.tiTriggersMatched[sourceType][tiType] = tiTriggersMatched[sourceType][tiType];
+			}
+		}
+		
+		// Return the copied clone.
+		return clone;
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were not matched.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getFailedReconSimulatedTriggers() {
+		return simTriggers[RECON] - matchedTriggers[RECON];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were not matched.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getFailedSSPSimulatedTriggers() {
+		return simTriggers[SSP] - matchedTriggers[SSP];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were matched.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getMatchedReconSimulatedTriggers() {
+		return matchedTriggers[RECON];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were matched for a given type of trigger when a given TI
+	 * bank flag was active.
+	 * @param tiTypeID - The identifier for the type of TI bank trigger
+	 * that should be active.
+	 * @param triggerTypeID - The identifier for the type of trigger.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getMatchedReconSimulatedTriggers(int tiTypeID) {
+		return tiTriggersMatched[RECON][tiTypeID];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were matched.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getMatchedSSPSimulatedTriggers() {
+		return matchedTriggers[SSP];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were matched for a given type of trigger when a given TI
+	 * bank flag was active.
+	 * @param tiTypeID - The identifier for the type of TI bank trigger
+	 * that should be active.
+	 * @param triggerTypeID - The identifier for the type of trigger.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getMatchedSSPSimulatedTriggers(int tiTypeID) {
+		return tiTriggersMatched[SSP][tiTypeID];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were matched, but did not see full cut alignment.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getPartiallyMatchedReconSimulatedTriggers() {
+		return simTriggers[RECON] - (matchedTriggers[RECON] + unmatchedTriggers[RECON]);
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were matched, but did not see full cut alignment.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getPartiallyMatchedSSPSimulatedTriggers() {
+		return simTriggers[SSP] - (matchedTriggers[SSP] + unmatchedTriggers[SSP]);
+	}
+	
+	/**
+	 * Gets the number of times the specified cut failed for triggers
+	 * that were partially matched for triggers simulated from FADC
+	 * reconstructed clusters.
+	 * @param cutIndex - The numerical cut identifier.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getReconCutFailures(int cutIndex) {
+		return getCutFailures(RECON, cutIndex);
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were seen.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getReconSimulatedTriggers() {
+		return simTriggers[RECON];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were seen for a given trigger type when a given TI bank
+	 * flag was active.
+	 * @param tiTypeID - The identifier for the type of TI bank trigger
+	 * that should be active.
+	 * @param triggerTypeID - The identifier for the type of trigger.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getReconSimulatedTriggers(int tiTypeID) {
+		return tiTriggersSeen[RECON][tiTypeID];
+	}
+	
+	/**
+	 * Gets the number of triggers reported by the SSP bank.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getReportedTriggers() {
+		return reportedTriggers;
+	}
+	
+	/**
+	 * Gets the number of times the specified cut failed for triggers
+	 * that were partially matched for triggers simulated from SSP
+	 * bank clusters.
+	 * @param cutIndex - The numerical cut identifier.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getSSPCutFailures(int cutIndex) {
+		return getCutFailures(SSP, cutIndex);
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were seen.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getSSPSimulatedTriggers() {
+		return simTriggers[SSP];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were seen for a given trigger type when a given TI bank
+	 * flag was active.
+	 * @param tiTypeID - The identifier for the type of TI bank trigger
+	 * that should be active.
+	 * @param triggerTypeID - The identifier for the type of trigger.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getSSPSimulatedTriggers(int tiTypeID) {
+		return tiTriggersSeen[SSP][tiTypeID];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from reconstructed clusters
+	 * that were completely unmatched.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getUnmatchedReconSimulatedTriggers() {
+		return unmatchedTriggers[RECON];
+	}
+	
+	/**
+	 * Gets the number of simulated triggers from SSP bank clusters
+	 * that were completely unmatched.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	public int getUnmatchedSSPSimulatedTriggers() {
+		return unmatchedTriggers[SSP];
+	}
+	
+	/**
+	 * Gets the number of times the specified cut failed for triggers
+	 * that were partially matched for triggers simulated from the type
+	 * of cluster indicated.
+	 * @param type - Either <code>SSP</code> or <code>RECON</code>.
+	 * @param cutIndex - The numerical cut identifier.
+	 * @return Returns the number of triggers as an <code>int</code>.
+	 */
+	private int getCutFailures(int type, int cutIndex) {
+		// Ensure that the cut index is valid.
+		if(cutIndex < 0 || cutIndex >= 4) {
+			throw new IndexOutOfBoundsException(String.format("Cut index \"%d\" is not recognized.", cutIndex));
+		}
+		
+		// Return the cut failures.
+		return failedCuts[type][cutIndex];
+	}
+}

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java	Thu Apr  2 10:05:53 2015
@@ -42,7 +42,7 @@
 	 */
 	public void addSinglesTriggers(int eventTriggerType, List<List<? extends Trigger<?>>> singlesTriggers) {
 		// Note the trigger type.
-		int[] triggerType = { TriggerDiagnosticUtil.TRIGGER_SINGLES_1, TriggerDiagnosticUtil.TRIGGER_SINGLES_2 };
+		int[] triggerType = { TriggerDiagnosticUtil.TRIGGER_SINGLES_0, TriggerDiagnosticUtil.TRIGGER_SINGLES_1 };
 		
 		// Track the total number of singles triggers seen.
 		addTriggers(eventTriggerType, singlesTriggers, triggerType);
@@ -57,7 +57,7 @@
 	 */
 	public void addPairTriggers(int eventTriggerType, List<List<? extends Trigger<?>>> pairTriggers) {
 		// Note the trigger type.
-		int[] triggerType = { TriggerDiagnosticUtil.TRIGGER_PAIR_1, TriggerDiagnosticUtil.TRIGGER_PAIR_2 };
+		int[] triggerType = { TriggerDiagnosticUtil.TRIGGER_PAIR_0, TriggerDiagnosticUtil.TRIGGER_PAIR_1 };
 		
 		// Track the total number of singles triggers seen.
 		addTriggers(eventTriggerType, pairTriggers, triggerType);
@@ -242,18 +242,18 @@
 			// triggers this is. Note that this assumes that the trigger
 			// number is stored as either 0 or 1.
 			if(trigger.getTriggerNumber() == 0) {
+				return TriggerDiagnosticUtil.TRIGGER_PAIR_0;
+			} else {
 				return TriggerDiagnosticUtil.TRIGGER_PAIR_1;
-			} else {
-				return TriggerDiagnosticUtil.TRIGGER_PAIR_2;
 			}
 		} else if(trigger instanceof SinglesTrigger) {
 			// Use the trigger number to determine which of the two
 			// triggers this is. Note that this assumes that the trigger
 			// number is stored as either 0 or 1.
 			if(trigger.getTriggerNumber() == 0) {
+				return TriggerDiagnosticUtil.TRIGGER_SINGLES_0;
+			} else {
 				return TriggerDiagnosticUtil.TRIGGER_SINGLES_1;
-			} else {
-				return TriggerDiagnosticUtil.TRIGGER_SINGLES_2;
 			}
 		}
 		

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java	Thu Apr  2 10:05:53 2015
@@ -27,9 +27,9 @@
 	public void addEvent(int eventType, TriggerMatchEvent event, List<List<? extends Trigger<?>>> reconTriggers,
 			List<List<? extends Trigger<?>>> sspSimTriggers, List<? extends SSPNumberedTrigger> sspBankTriggers) {
 		// Increment the event type count.
-		if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_1) {
+		if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_0 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_0) {
 			triggerTypesSeen[0]++;
-		} else if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_2 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_2) {
+		} else if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_1) {
 			triggerTypesSeen[1]++;
 		}
 		
@@ -70,9 +70,9 @@
 		// Check if a trigger of the right time was found.
 		// Get the trigger number and type.
 		if(event.sawEventType()) {
-			if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_1) {
+			if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_0 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_0) {
 				triggerTypesFound[0]++;
-			} else if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_2 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_2) {
+			} else if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_1) {
 				triggerTypesFound[1]++;
 			}
 		}

Modified: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java
 =============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java	(original)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java	Thu Apr  2 10:05:53 2015
@@ -2,6 +2,7 @@
 
 import java.awt.Point;
 
+import org.hps.analysis.trigger.data.TriggerStatModule;
 import org.hps.recon.ecal.triggerbank.SSPCluster;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
@@ -32,13 +33,13 @@
 	public static final int PAIR_COPLANARITY = 3;
 	
 	// Trigger type variables.
-	public static final int TRIGGER_PULSER    = 0;
-	public static final int TRIGGER_COSMIC    = 1;
-	public static final int TRIGGER_SINGLES_1 = 2;
-	public static final int TRIGGER_SINGLES_2 = 3;
-	public static final int TRIGGER_PAIR_1    = 4;
-	public static final int TRIGGER_PAIR_2    = 5;
-	public static final String[] TRIGGER_NAME = { "Pulser", "Cosmic", "Singles 1", "Singles 2", "Pair 1", "Pair 2" };
+	public static final int TRIGGER_PULSER    = TriggerStatModule.PULSER;
+	public static final int TRIGGER_COSMIC    = TriggerStatModule.COSMIC;
+	public static final int TRIGGER_SINGLES_0 = TriggerStatModule.SINGLES_0;
+	public static final int TRIGGER_SINGLES_1 = TriggerStatModule.SINGLES_1;
+	public static final int TRIGGER_PAIR_0    = TriggerStatModule.PAIR_0;
+	public static final int TRIGGER_PAIR_1    = TriggerStatModule.PAIR_1;
+	public static final String[] TRIGGER_NAME = { "Singles 0", "Singles 1", "Pair 0", "Pair 1", "Pulser", "Cosmic" };
 	
 	/**
 	 * Convenience method that writes the position of a cluster in the