Author: [log in to unmask]
Date: Thu Mar 5 10:59:19 2015
New Revision: 2266
Log:
Trigger diagnostic package is being relocated to an official location now that it is approaching release status.
Added:
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/DiagSnapshot.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterStatModule.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/TriggerMatchEvent.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/ComponentUtils.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/OutputLogger.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Pair.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Trigger.java
java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/DiagSnapshot.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/DiagSnapshot.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/DiagSnapshot.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,169 @@
+package org.hps.analysis.trigger;
+
+import org.hps.analysis.trigger.event.ClusterMatchStatus;
+import org.hps.analysis.trigger.event.ClusterStatModule;
+import org.hps.analysis.trigger.event.TriggerEfficiencyModule;
+import org.hps.analysis.trigger.event.TriggerMatchStatus;
+import org.hps.analysis.trigger.event.TriggerStatModule;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+
+
+/**
+ * Class <code>DiagSnapshot</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 DiagSnapshot {
+ public final ClusterStatModule clusterRunStatistics;
+ public final ClusterStatModule clusterLocalStatistics;
+ public final SinglesTriggerStatModule singlesRunStatistics;
+ public final SinglesTriggerStatModule singlesLocalStatistics;
+ public final PairTriggerStatModule pairRunStatistics;
+ public final PairTriggerStatModule pairLocalStatistics;
+ public final TriggerEfficiencyModule efficiencyRunStatistics;
+ public final TriggerEfficiencyModule efficiencyLocalStatistics;
+
+ /**
+ * Instantiates a new snapshot. The snapshot creates a copy of the
+ * statistical information stored in the status objects and makes
+ * a copy of this information available to other classes.
+ * @param localCluster - The local cluster data object.
+ * @param globalCluster - The run cluster data object.
+ * @param localSingles - The local singles trigger data object.
+ * @param globalSingles - The run singles trigger data object.
+ * @param localPair - The local pair trigger data object.
+ * @param globalPair - The run pair trigger data object.
+ */
+ DiagSnapshot(ClusterMatchStatus localCluster, ClusterMatchStatus globalCluster,
+ TriggerMatchStatus localSingles, TriggerMatchStatus globalSingles,
+ TriggerMatchStatus localPair, TriggerMatchStatus globalPair,
+ TriggerEfficiencyModule localEfficiency, TriggerEfficiencyModule globalEfficiency) {
+ clusterRunStatistics = globalCluster.cloneStatModule();
+ clusterLocalStatistics = localCluster.cloneStatModule();
+ singlesRunStatistics = new SinglesTriggerStatModule(globalSingles);
+ singlesLocalStatistics = new SinglesTriggerStatModule(localSingles);
+ pairRunStatistics = new PairTriggerStatModule(globalPair);
+ pairLocalStatistics = new PairTriggerStatModule(localPair);
+ efficiencyRunStatistics = globalEfficiency.clone();
+ efficiencyLocalStatistics = localEfficiency.clone();
+ }
+
+ /**
+ *
+ * Class <code>SinglesTriggerStatModule</code> is a wrapper for the
+ * generic <code>TriggerStatModule</code> that provides specific
+ * methods to obtain cut results rather than needing to reference
+ * a cut index.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+ public class SinglesTriggerStatModule extends TriggerStatModule {
+ /**
+ * Instantiates a <code>SinglesTriggerStatModule</code> with
+ * statistics cloned from the base object.
+ * @param base - The source for the statistical data.
+ */
+ SinglesTriggerStatModule(TriggerStatModule base) {
+ super(base);
+ }
+
+ /**
+ * Gets the number of times the cluster energy upper bound cut
+ * failed to match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getEMaxFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.SINGLES_ENERGY_MAX);
+ }
+
+ /**
+ * Gets the number of times the cluster energy lower bound cut
+ * failed to match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getEMinFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.SINGLES_ENERGY_MIN);
+ }
+
+ /**
+ * Gets the number of times the cluster hit count cut failed
+ * to match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getHitCountFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.SINGLES_HIT_COUNT);
+ }
+ }
+
+ /**
+ *
+ * Class <code>PairTriggerStatModule</code> is a wrapper for the
+ * generic <code>TriggerStatModule</code> that provides specific
+ * methods to obtain cut results rather than needing to reference
+ * a cut index.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+ public class PairTriggerStatModule extends TriggerStatModule {
+ /**
+ * Instantiates a <code>PairTriggerStatModule</code> with
+ * statistics cloned from the base object.
+ * @param base - The source for the statistical data.
+ */
+ PairTriggerStatModule(TriggerStatModule base) {
+ super(base);
+ }
+
+ /**
+ * Gets the number of times the pair energy sum cut failed to
+ * match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getESumFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.PAIR_ENERGY_SUM);
+ }
+
+ /**
+ * Gets the number of times the pair energy difference cut failed
+ * to match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getEDiffFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.PAIR_ENERGY_DIFF);
+ }
+
+ /**
+ * Gets the number of times the pair energy slope cut failed
+ * to match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getESlopeFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.PAIR_ENERGY_SLOPE);
+ }
+
+ /**
+ * Gets the number of times the pair coplanarity cut failed to
+ * match.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getCoplanarityFailures(int triggerNumber) {
+ return getCutFailures(triggerNumber, TriggerDiagnosticUtil.PAIR_COPLANARITY);
+ }
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,1995 @@
+package org.hps.analysis.trigger;
+
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+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.util.OutputLogger;
+import org.hps.analysis.trigger.util.Pair;
+import org.hps.analysis.trigger.util.PairTrigger;
+import org.hps.analysis.trigger.util.SinglesTrigger;
+import org.hps.analysis.trigger.util.Trigger;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.hps.readout.ecal.TriggerModule;
+import org.hps.readout.ecal.daqconfig.ConfigurationManager;
+import org.hps.readout.ecal.daqconfig.DAQConfig;
+import org.hps.readout.ecal.triggerbank.AbstractIntData;
+import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.hps.readout.ecal.triggerbank.SSPData;
+import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.readout.ecal.triggerbank.SSPPairTrigger;
+import org.hps.readout.ecal.triggerbank.SSPSinglesTrigger;
+import org.hps.readout.ecal.triggerbank.SSPTrigger;
+import org.hps.readout.ecal.triggerbank.TIData;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.GenericObject;
+import org.lcsim.util.Driver;
+
+public class TriggerDiagnosticDriver extends Driver {
+ // Store the LCIO collection names for the needed objects.
+ private String hitCollectionName = "EcalCalHits";
+ private String bankCollectionName = "TriggerBank";
+ private String clusterCollectionName = "EcalClusters";
+ private String diagnosticCollectionName = "DiagnosticSnapshot";
+
+ // Store the lists of parsed objects.
+ private TIData tiBank;
+ private SSPData sspBank;
+ private List<Cluster> reconClusters = new ArrayList<Cluster>();
+ private List<SSPCluster> sspClusters;
+ private List<List<PairTrigger<Cluster[]>>> reconPairsTriggers = new ArrayList<List<PairTrigger<Cluster[]>>>(2);
+ private List<List<PairTrigger<SSPCluster[]>>> sspPairsTriggers = new ArrayList<List<PairTrigger<SSPCluster[]>>>(2);
+ private List<List<SinglesTrigger<Cluster>>> reconSinglesTriggers = new ArrayList<List<SinglesTrigger<Cluster>>>(2);
+ private List<List<SinglesTrigger<SSPCluster>>> sspSinglesTriggers = new ArrayList<List<SinglesTrigger<SSPCluster>>>(2);
+
+ // Trigger modules for performing trigger analysis.
+ private int activeTrigger = -1;
+ private TriggerModule[] singlesTrigger = new TriggerModule[2];
+ private TriggerModule[] pairsTrigger = new TriggerModule[2];
+
+ // Verification settings.
+ private int nsa = 100;
+ private int nsb = 20;
+ private int windowWidth = 200;
+ private int hitAcceptance = 1;
+ private int noiseThreshold = 50;
+ private long localWindowStart = 0;
+ private boolean readDAQConfig = false;
+ private double energyAcceptance = 0.03;
+ private int localWindowThreshold = 30000;
+ private boolean performClusterVerification = true;
+ private boolean performSinglesTriggerVerification = true;
+ private boolean performPairTriggerVerification = true;
+
+ // 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;
+
+ // Verbose settings.
+ private boolean clusterFail = false;
+ private boolean singlesEfficiencyFail = false;
+ private boolean singlesInternalFail = false;
+ private boolean pairEfficiencyFail = false;
+ private boolean pairInternalFail = false;
+ private boolean verbose = false;
+ private boolean printClusterFail = true;
+ private boolean printSinglesTriggerEfficiencyFail = true;
+ private boolean printSinglesTriggerInternalFail = true;
+ private boolean printPairTriggerEfficiencyFail = true;
+ private boolean printPairTriggerInternalFail = true;
+
+ // Cut index arrays for trigger verification.
+ private static final int ENERGY_MIN = TriggerDiagnosticUtil.SINGLES_ENERGY_MIN;
+ private static final int ENERGY_MAX = TriggerDiagnosticUtil.SINGLES_ENERGY_MAX;
+ private static final int HIT_COUNT = TriggerDiagnosticUtil.SINGLES_HIT_COUNT;
+ private static final int ENERGY_SUM = TriggerDiagnosticUtil.PAIR_ENERGY_SUM;
+ private static final int ENERGY_DIFF = TriggerDiagnosticUtil.PAIR_ENERGY_DIFF;
+ private static final int ENERGY_SLOPE = TriggerDiagnosticUtil.PAIR_ENERGY_SLOPE;
+ private static final int COPLANARITY = TriggerDiagnosticUtil.PAIR_COPLANARITY;
+
+ /**
+ * Define the trigger modules. This should be replaced by parsing
+ * the DAQ configuration at some point.
+ */
+ @Override
+ public void startOfData() {
+ // If the DAQ configuration should be read, attach a listener
+ // to track when it updates.
+ if(readDAQConfig) {
+ ConfigurationManager.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ // Get the DAQ configuration.
+ DAQConfig daq = ConfigurationManager.getInstance();
+
+ // Load the DAQ settings from the configuration manager.
+ singlesTrigger[0].loadDAQConfiguration(daq.getSSPConfig().getSingles1Config());
+ singlesTrigger[1].loadDAQConfiguration(daq.getSSPConfig().getSingles2Config());
+ pairsTrigger[0].loadDAQConfiguration(daq.getSSPConfig().getPair1Config());
+ pairsTrigger[1].loadDAQConfiguration(daq.getSSPConfig().getPair2Config());
+ nsa = daq.getFADCConfig().getNSA();
+ nsb = daq.getFADCConfig().getNSB();
+ windowWidth = daq.getFADCConfig().getWindowWidth();
+
+ // Print a DAQ configuration settings header.
+ System.out.println();
+ System.out.println();
+ System.out.println("======================================================================");
+ System.out.println("=== DAQ Configuration Settings =======================================");
+ System.out.println("======================================================================");
+ logSettings();
+ }
+ });
+ }
+
+ // Print the cluster verification header.
+ System.out.println();
+ System.out.println();
+ System.out.println("======================================================================");
+ System.out.println("=== Cluster/Trigger Verification Settings ============================");
+ System.out.println("======================================================================");
+
+ // Set the FADC settings.
+ nsa = 100;
+ nsb = 20;
+ windowWidth = 400;
+
+ /*
+ // Define the first singles trigger.
+ singlesTrigger[0] = new TriggerModule();
+ singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.010);
+ singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 8.191);
+ singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 2);
+
+ // Define the second singles trigger.
+ singlesTrigger[1] = new TriggerModule();
+ singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.010);
+ singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 0.050);
+ singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 2);
+
+ // Define the first pairs trigger.
+ pairsTrigger[0] = new TriggerModule();
+ pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.020);
+ pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 0.055);
+ pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 1);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, 0.010);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, 2.000);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, 1.200);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, 0.400);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, 0.0055);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, 40);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, 16);
+
+ // Define the second pairs trigger.
+ pairsTrigger[1] = new TriggerModule();
+ pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.010);
+ pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 1.800);
+ pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 2);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, 0.020);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, 2.000);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, 1.200);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, 0.400);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, 0.0055);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, 40);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, 16);
+ */
+
+ // Define the first singles trigger.
+ singlesTrigger[0] = new TriggerModule();
+ singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.500);
+ singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 8.191);
+ singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 0);
+
+ // Define the second singles trigger.
+ singlesTrigger[1] = new TriggerModule();
+ singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.000);
+ singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 8.191);
+ singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 0);
+
+ // Define the first pairs trigger.
+ pairsTrigger[0] = new TriggerModule();
+ pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.000);
+ pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 8.191);
+ pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 0);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, 0.000);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, 8.191);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, 8.191);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, 0.000);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, 0.001);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, 180);
+ pairsTrigger[0].setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, 8);
+
+ // Define the second pairs trigger.
+ pairsTrigger[1] = new TriggerModule();
+ pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.000);
+ pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 8.191);
+ pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 0);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, 0.000);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, 8.191);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, 8.191);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, 0.000);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, 0.001);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, 180);
+ pairsTrigger[1].setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, 8);
+
+ // Instantiate the triggers lists.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ reconPairsTriggers.add(new ArrayList<PairTrigger<Cluster[]>>());
+ sspPairsTriggers.add(new ArrayList<PairTrigger<SSPCluster[]>>());
+ reconSinglesTriggers.add(new ArrayList<SinglesTrigger<Cluster>>());
+ sspSinglesTriggers.add(new ArrayList<SinglesTrigger<SSPCluster>>());
+ }
+
+ // Print the initial settings.
+ logSettings();
+ }
+
+ /**
+ * Prints the total run statistics.
+ */
+ @Override
+ public void endOfData() {
+ // Print the cluster/trigger verification header.
+ System.out.println();
+ System.out.println();
+ System.out.println("======================================================================");
+ System.out.println("=== Cluster/Trigger Verification Results =============================");
+ System.out.println("======================================================================");
+
+ // Print the general event failure rate.
+ System.out.println("Event Failure Rate:");
+ System.out.printf("\tNoise Events :: %d / %d (%7.3f%%)%n",
+ noiseEvents, totalEvents, (100.0 * noiseEvents / totalEvents));
+ System.out.printf("\tCluster Events Failed :: %d / %d (%7.3f%%)%n",
+ failedClusterEvents, totalEvents, (100.0 * failedClusterEvents / totalEvents));
+ System.out.printf("\tSingles Events Failed :: %d / %d (%7.3f%%)%n",
+ failedSinglesEvents, totalEvents, (100.0 * failedSinglesEvents / totalEvents));
+ System.out.printf("\tPair Events Failed :: %d / %d (%7.3f%%)%n",
+ failedPairEvents, totalEvents, (100.0 * failedPairEvents / totalEvents));
+
+ // Print the cluster verification data.
+ 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()); }
+
+ // 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());
+ 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())); }
+
+ // Print the individual cut performances.
+ int halfSSPTriggers = triggerRunStats[triggerType].getSSPSimTriggerCount() / 2;
+ if(triggerType == 0) {
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ System.out.println();
+ System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
+ if(triggerRunStats[0].getSSPSimTriggerCount() == 0) {
+ System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), halfSSPTriggers);
+ System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), halfSSPTriggers);
+ System.out.printf("\t\tCluster Hit Count :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), halfSSPTriggers);
+ } else {
+ System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), halfSSPTriggers,
+ (100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN) / halfSSPTriggers));
+ System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), halfSSPTriggers,
+ (100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX) / halfSSPTriggers));
+ System.out.printf("\t\tCluster Hit Count :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), halfSSPTriggers,
+ (100.0 * triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT) / halfSSPTriggers));
+ }
+ }
+ } else {
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ System.out.println();
+ System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
+ if(triggerRunStats[1].getSSPSimTriggerCount() == 0) {
+ System.out.printf("\t\tPair Energy Sum :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), halfSSPTriggers);
+ System.out.printf("\t\tPair Energy Difference :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), halfSSPTriggers);
+ System.out.printf("\t\tPair Energy Slope :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), halfSSPTriggers);
+ System.out.printf("\t\tPair Coplanarity :: %" + spaces + "d / %" + spaces + "d%n",
+ triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), halfSSPTriggers);
+ } else {
+ System.out.printf("\t\tPair Energy Sum :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), halfSSPTriggers,
+ (100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM) / halfSSPTriggers));
+ System.out.printf("\t\tPair Energy Difference :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), halfSSPTriggers,
+ (100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF) / halfSSPTriggers));
+ System.out.printf("\t\tPair Energy Slope :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), halfSSPTriggers,
+ (100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE) / halfSSPTriggers));
+ System.out.printf("\t\tPair Coplanarity :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+ triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), halfSSPTriggers,
+ (100.0 * triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY) / halfSSPTriggers));
+ }
+ }
+ }
+ }
+
+ this.efficiencyRunStats.printModule();
+ }
+
+ /**
+ * Gets the banks and clusters from the event.
+ */
+ @Override
+ public void process(EventHeader event) {
+ // ==========================================================
+ // ==== Initialize the Event ================================
+ // ==========================================================
+
+ // If DAQ settings are to be used, check if they are initialized
+ // yet. If not, skip the event.
+ if(readDAQConfig) {
+ if(!ConfigurationManager.isInitialized()) {
+ return;
+ }
+ }
+
+ // Print the verification header.
+ OutputLogger.printNewLine(2);
+ OutputLogger.println("======================================================================");
+ OutputLogger.println("==== Cluster/Trigger Verification ====================================");
+ OutputLogger.println("======================================================================");
+
+ // Increment the total event count.
+ totalEvents++;
+
+ // Reset the output buffer and print flags.
+ clusterFail = false;
+ singlesInternalFail = false;
+ singlesEfficiencyFail = false;
+ pairInternalFail = false;
+ pairEfficiencyFail = false;
+
+
+
+ // ==========================================================
+ // ==== Obtain SSP and TI Banks =============================
+ // ==========================================================
+
+ // Get the SSP clusters.
+ if(event.hasCollection(GenericObject.class, bankCollectionName)) {
+ // Get the bank list.
+ List<GenericObject> bankList = event.get(GenericObject.class, bankCollectionName);
+
+ // Search through the banks and get the SSP and TI banks.
+ for(GenericObject obj : bankList) {
+ // If this is an SSP bank, parse it.
+ if(AbstractIntData.getTag(obj) == SSPData.BANK_TAG) {
+ sspBank = new SSPData(obj);
+ }
+
+ // Otherwise, if this is a TI bank, parse it.
+ else if(AbstractIntData.getTag(obj) == TIData.BANK_TAG) {
+ tiBank = new TIData(obj);
+
+ if(tiBank.isPulserTrigger()) {
+ OutputLogger.println("Trigger type :: Pulser");
+ activeTrigger = TriggerDiagnosticUtil.TRIGGER_PULSER;
+ } else if(tiBank.isSingle0Trigger()) {
+ OutputLogger.println("Trigger type :: Singles 1");
+ activeTrigger = TriggerDiagnosticUtil.TRIGGER_SINGLES_1;
+ } else if(tiBank.isSingle1Trigger()) {
+ OutputLogger.println("Trigger type :: Singles 2");
+ activeTrigger = TriggerDiagnosticUtil.TRIGGER_SINGLES_2;
+ } else if(tiBank.isPair0Trigger()) {
+ OutputLogger.println("Trigger type :: Pair 1");
+ activeTrigger = TriggerDiagnosticUtil.TRIGGER_PAIR_1;
+ } else if(tiBank.isPair1Trigger()) {
+ OutputLogger.println("Trigger type :: Pair 2");
+ activeTrigger = TriggerDiagnosticUtil.TRIGGER_PAIR_2;
+ } else if(tiBank.isCalibTrigger()) {
+ OutputLogger.println("Trigger type :: Cosmic");
+ activeTrigger = TriggerDiagnosticUtil.TRIGGER_COSMIC;
+ }
+ }
+ }
+
+ // If there is an SSP bank, get the list of SSP clusters.
+ if(sspBank != null) {
+ sspClusters = sspBank.getClusters();
+ if(sspClusters.size() == 1) {
+ OutputLogger.println("1 SSP cluster found.");
+ } else {
+ OutputLogger.printf("%d SSP clusters found.%n", sspClusters.size());
+ }
+ }
+ }
+
+
+
+ // ==========================================================
+ // ==== Establish Event Integrity ===========================
+ // ==========================================================
+
+ // Check that all of the required objects are present.
+ if(sspBank == null) {
+ OutputLogger.println("No SSP bank found for this event. No verification will be performed.");
+ if(verbose) { OutputLogger.printLog(); }
+ return;
+ } if(tiBank == null) {
+ OutputLogger.println("No TI bank found for this event. No verification will be performed.");
+ if(verbose) { OutputLogger.printLog(); }
+ return;
+ }
+
+
+
+ // ==========================================================
+ // ==== Check the Noise Level ===============================
+ // ==========================================================
+
+ // Check if there are hits.
+ 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++;
+ OutputLogger.println("Noise event detected. Skipping event...");
+ if(verbose) { OutputLogger.printLog(); }
+ return;
+ }
+ }
+
+
+
+ // ==========================================================
+ // ==== Obtain Reconstructed Clusters =======================
+ // ==========================================================
+
+ // Clear the list of triggers from previous events.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ sspSinglesTriggers.get(triggerNum).clear();
+ reconSinglesTriggers.get(triggerNum).clear();
+ sspPairsTriggers.get(triggerNum).clear();
+ reconPairsTriggers.get(triggerNum).clear();
+ }
+
+ // Get the reconstructed clusters.
+ if(event.hasCollection(Cluster.class, clusterCollectionName)) {
+ // Get the reconstructed clusters.
+ List<Cluster> allClusters = event.get(Cluster.class, clusterCollectionName);
+
+ // Keep only the clusters that can be verified.
+ OutputLogger.println();
+ OutputLogger.println("Process cluster for verifiability:");
+ reconClusters.clear();
+ for(Cluster reconCluster : allClusters) {
+ // Check that the cluster is within the safe region of the
+ // FADC readout window. If it is not, it will likely have
+ // inaccurate energy or hit values and may not produce the
+ // expected results.
+ OutputLogger.printf("\t%s", TriggerDiagnosticUtil.clusterToString(reconCluster));
+ if(isVerifiable(reconCluster)) {
+ reconClusters.add(reconCluster);
+ OutputLogger.println(" [ verifiable ]");
+ } else { OutputLogger.println(" [ unverifiable ]"); }
+
+ }
+
+ // Output the number of verifiable clusters found.
+ if(reconClusters.size() == 1) { OutputLogger.println("1 verifiable reconstructed cluster found."); }
+ else { OutputLogger.printf("%d verifiable reconstructed clusters found.%n", reconClusters.size()); }
+
+ // Output the number of unverifiable clusters found.
+ int unverifiableClusters = allClusters.size() - reconClusters.size();
+ if(unverifiableClusters == 1) { OutputLogger.println("1 unverifiable reconstructed cluster found."); }
+ else { OutputLogger.printf("%d unverifiable reconstructed clusters found.%n", unverifiableClusters); }
+ } else {
+ reconClusters = new ArrayList<Cluster>(0);
+ OutputLogger.printf("No reconstructed clusters were found for collection \"%s\" in this event.%n", clusterCollectionName);
+ }
+
+
+
+ // ==========================================================
+ // ==== Perform Event Verification ==========================
+ // ==========================================================
+
+ // Perform the cluster verification step.
+ if(performClusterVerification) { clusterVerification(); }
+
+ // Construct lists of triggers for the SSP clusters and the
+ // reconstructed clusters.
+ if(performSinglesTriggerVerification) {
+ constructSinglesTriggers();
+ singlesTriggerVerification();
+ }
+ if(performPairTriggerVerification) {
+ constructPairTriggers();
+ pairTriggerVerification();
+ }
+
+ // Track how many events failed due to each type of verification.
+ if(clusterFail) { failedClusterEvents++; }
+ if(pairInternalFail || pairEfficiencyFail) { failedPairEvents++; }
+ if(singlesInternalFail || singlesEfficiencyFail) { failedSinglesEvents++; }
+
+
+
+ // ==========================================================
+ // ==== Perform Event Write-Out =============================
+ // ==========================================================
+
+ if(verbose ||(clusterFail && printClusterFail) ||
+ (singlesInternalFail && printSinglesTriggerInternalFail) ||
+ (singlesEfficiencyFail && printSinglesTriggerEfficiencyFail) ||
+ (pairInternalFail && printPairTriggerInternalFail) ||
+ (pairEfficiencyFail && printPairTriggerEfficiencyFail)) {
+ OutputLogger.printLog();
+ }
+
+
+
+ // ==========================================================
+ // ==== Process Local Tracked Variables =====================
+ // ==========================================================
+ if(Calendar.getInstance().getTimeInMillis() - localWindowStart > 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);
+
+ // Push the snapshot to the data stream.
+ List<DiagSnapshot> snapshotCollection = new ArrayList<DiagSnapshot>(1);
+ snapshotCollection.add(snapshot);
+ event.put(diagnosticCollectionName, snapshotCollection);
+
+ // Clear the local statistical data.
+ clusterLocalStats.clear();
+ triggerLocalStats[0].clear();
+ triggerLocalStats[1].clear();
+ efficiencyLocalStats.clear();
+
+ // Update the last write time.
+ localWindowStart = Calendar.getInstance().getTimeInMillis();
+ }
+ }
+
+ public void setPrintOnClusterFailure(boolean state) {
+ printClusterFail = state;
+ }
+
+ public void setPrintOnSinglesEfficiencyFailure(boolean state) {
+ printSinglesTriggerEfficiencyFail = state;
+ }
+
+ public void setPrintOnSinglesSSPFailure(boolean state) {
+ printSinglesTriggerInternalFail = state;
+ }
+
+ public void setPrintOnPairEfficiencyFailure(boolean state) {
+ printPairTriggerEfficiencyFail = state;
+ }
+
+ public void setPrintOnPairSSPFailure(boolean state) {
+ printPairTriggerInternalFail = state;
+ }
+
+ public void setVerbose(boolean state) {
+ verbose = state;
+ }
+
+ public void setHitCollectionName(String hitCollectionName) {
+ this.hitCollectionName = hitCollectionName;
+ }
+
+ public void setClusterCollectionName(String clusterCollectionName) {
+ this.clusterCollectionName = clusterCollectionName;
+ }
+
+ public void setBankCollectionName(String bankCollectionName) {
+ this.bankCollectionName = bankCollectionName;
+ }
+
+ public void setNoiseThresholdCount(int noiseHits) {
+ noiseThreshold = noiseHits;
+ }
+
+ public void setHitAcceptanceWindow(int window) {
+ hitAcceptance = window;
+ }
+
+ public void setEnergyAcceptanceWindow(double window) {
+ energyAcceptance = window;
+ }
+
+ public void setReadDAQConfig(boolean state) {
+ readDAQConfig = state;
+ }
+
+ /**
+ * Attempts to match all reconstructed clusters that are safely
+ * within the integration window with clusters reported by the SSP.
+ * Method also tracks the ratio of valid reconstructed clusters to
+ * matches found.<br/>
+ * <br/>
+ * Note that unmatched SSP clusters are ignored. Since these may
+ * or may not correspond to reconstructed clusters that occur in
+ * the forbidden time region, it is impossible to say whether or
+ * not these legitimately failed to match or not.
+ */
+ private void clusterVerification() {
+ // ==========================================================
+ // ==== Initialize Cluster Verification =====================
+ // ==========================================================
+
+ // Print the cluster verification header.
+ OutputLogger.printNewLine(2);
+ OutputLogger.println("======================================================================");
+ OutputLogger.println("=== Cluster Verification =============================================");
+ OutputLogger.println("======================================================================");
+
+ // Track the number of cluster pairs that were matched and that
+ // failed by failure type.
+ ClusterMatchEvent event = new ClusterMatchEvent();
+
+
+
+ // ==========================================================
+ // ==== Produce the Cluster Position Mappings ===============
+ // ==========================================================
+
+ // Create maps to link cluster position to the list of clusters
+ // that were found at that location.
+ Map<Point, List<Cluster>> reconClusterMap = new HashMap<Point, List<Cluster>>(reconClusters.size());
+ Map<Point, List<SSPCluster>> sspClusterMap = new HashMap<Point, List<SSPCluster>>(reconClusters.size());
+
+ // Populate the reconstructed cluster map.
+ for(Cluster reconCluster : reconClusters) {
+ // Get the cluster position.
+ Point position = new Point(TriggerDiagnosticUtil.getXIndex(reconCluster),
+ TriggerDiagnosticUtil.getYIndex(reconCluster));
+
+ // Get the list for this cluster position.
+ List<Cluster> reconList = reconClusterMap.get(position);
+ if(reconList == null) {
+ reconList = new ArrayList<Cluster>();
+ reconClusterMap.put(position, reconList);
+ }
+
+ // Add the cluster to the list.
+ reconList.add(reconCluster);
+ }
+
+ // Populate the SSP cluster map.
+ for(SSPCluster sspCluster : sspClusters) {
+ // Get the cluster position.
+ Point position = new Point(sspCluster.getXIndex(), sspCluster.getYIndex());
+
+ // Get the list for this cluster position.
+ List<SSPCluster> sspList = sspClusterMap.get(position);
+ if(sspList == null) {
+ sspList = new ArrayList<SSPCluster>();
+ sspClusterMap.put(position, sspList);
+ }
+
+ // Add the cluster to the list.
+ sspList.add(sspCluster);
+ }
+
+
+
+ // ==========================================================
+ // ==== Perform Cluster Matching ============================
+ // ==========================================================
+
+ // For each reconstructed cluster, attempt to match the clusters
+ // with SSP clusters at the same position.
+ positionLoop:
+ for(Entry<Point, List<Cluster>> clusterSet : reconClusterMap.entrySet()) {
+ // Get the reconstructed and SSP clusters at this position.
+ List<Cluster> reconList = clusterSet.getValue();
+ List<SSPCluster> sspList = sspClusterMap.get(clusterSet.getKey());
+
+ // Print the crystal position header.
+ OutputLogger.println();
+ OutputLogger.printf("Considering clusters at (%3d, %3d)%n", clusterSet.getKey().x, clusterSet.getKey().y);
+
+ // If there are no SSP clusters, then matching fails by
+ // reason of position. The remainder of the loop may be
+ // skipped, since there is nothing to check.
+ if(sspList == null || sspList.isEmpty()) {
+ clusterFail = true;
+ for(Cluster cluster : reconList) {
+ event.pairFailPosition(cluster, null);
+ }
+ continue positionLoop;
+ }
+
+ // If there are more reconstructed clusters than there are
+ // SSP clusters, than a number equal to the difference must
+ // fail by means of positions.
+ if(sspList.size() < reconList.size()) { clusterFail = true; }
+
+ // Get all possible permutations of SSP clusters.
+ List<List<Pair<Cluster, SSPCluster>>> permutations = getPermutations(reconList, sspList);
+
+ // Print the information for this crystal position.
+ OutputLogger.printf("\tRecon Clusters :: %d%n", reconList.size());
+ OutputLogger.printf("\tSSP Clusters :: %d%n", sspList.size());
+ OutputLogger.printf("\tPermutations :: %d%n", permutations.size());
+
+ // Track the plotted values for the current best permutation.
+ ClusterMatchEvent bestPerm = null;
+
+ // Iterate over the permutations and find the permutation
+ // that produces the best possible result when compared to
+ // the reconstructed clusters.
+ int permIndex = 0;
+ for(List<Pair<Cluster, SSPCluster>> pairs : permutations) {
+ // Update the current permutation number.
+ permIndex++;
+
+ // Track the plot values for this permutation.
+ ClusterMatchEvent perm = new ClusterMatchEvent();
+
+ // Try to match each pair.
+ pairLoop:
+ for(Pair<Cluster, SSPCluster> pair : pairs) {
+ // Print the current reconstructed/SSP cluster pair.
+ OutputLogger.printf("\tP%d :: %s --> %s", permIndex,
+ pair.getFirstElement() == null ? "None" : TriggerDiagnosticUtil.clusterToString(pair.getFirstElement()),
+ pair.getSecondElement() == null ? "None" : TriggerDiagnosticUtil.clusterToString(pair.getSecondElement()));
+
+ // If either cluster in the pair is null, there
+ // are not enough clusters to perform this match.
+ if(pair.getFirstElement() == null || pair.getSecondElement() == null) {
+ OutputLogger.printf(" [ %18s ]%n", "failure: unpaired");
+ perm.pairFailPosition(pair.getFirstElement(), pair.getSecondElement());
+ continue pairLoop;
+ }
+
+ // Check if the reconstructed cluster has an energy
+ // within the allotted threshold of the SSP cluster.
+ if(pair.getSecondElement().getEnergy() >= pair.getFirstElement().getEnergy() * (1 - energyAcceptance) &&
+ pair.getSecondElement().getEnergy() <= pair.getFirstElement().getEnergy() * (1 + energyAcceptance)) {
+ // Check that the hit count of the reconstructed
+ // is within the allotted threshold of the SSP
+ // cluster.
+ if(pair.getSecondElement().getHitCount() >= pair.getFirstElement().getCalorimeterHits().size() - hitAcceptance &&
+ pair.getSecondElement().getHitCount() <= pair.getFirstElement().getCalorimeterHits().size() + hitAcceptance) {
+ // Designate the pair as a match.
+ perm.pairMatch(pair.getFirstElement(), pair.getSecondElement());
+ OutputLogger.printf(" [ %18s ]%n", "success: matched");
+ } else {
+ perm.pairFailHitCount(pair.getFirstElement(), pair.getSecondElement());
+ OutputLogger.printf(" [ %18s ]%n", "failure: hit count");
+ } // End hit count check.
+ } else {
+ perm.pairFailEnergy(pair.getFirstElement(), pair.getSecondElement());
+ OutputLogger.printf(" [ %18s ]%n", "failure: energy");
+ } // End energy check.
+ } // End Pair Loop
+
+ // Print the results of the permutation.
+ OutputLogger.printf("\t\tPermutation Matched :: %d%n", perm.getMatches());
+ OutputLogger.printf("\t\tPermutation Energy :: %d%n", perm.getEnergyFailures());
+ OutputLogger.printf("\t\tPermutation Hit Count :: %d%n", perm.getHitCountFailures());
+
+ // Check whether the results from this permutation
+ // exceed the quality of the last best results. A
+ // greater number of matches is always better. If the
+ // matches are the same, select the one with fewer
+ // failures due to energy.
+ bestPerm = getBestPermutation(bestPerm, perm);
+ } // End Permutation Loop
+
+ // Print the final results for the position.
+ OutputLogger.printf("\tPosition Matched :: %d%n", bestPerm.getMatches());
+ OutputLogger.printf("\tPosition Energy :: %d%n", bestPerm.getEnergyFailures());
+ OutputLogger.printf("\tPosition Hit Count :: %d%n", bestPerm.getHitCountFailures());
+
+ // Add the results from the best-matched permutation
+ // to the event efficiency results.
+ event.addEvent(bestPerm);
+ } // End Crystal Position Loop
+
+ // Add the event results to the global results.
+ clusterRunStats.addEvent(event, reconClusters, sspClusters);
+ clusterLocalStats.addEvent(event, reconClusters, sspClusters);
+
+
+
+ // ==========================================================
+ // ==== Output Event Summary ================================
+ // ==========================================================
+
+ // Print the valid reconstructed clusters and populate their
+ // distribution graphs.
+ OutputLogger.println();
+ OutputLogger.println("Verified Reconstructed Clusters:");
+ if(!reconClusters.isEmpty()) {
+ for(Cluster reconCluster : reconClusters) {
+ OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(reconCluster));
+ }
+ } else { OutputLogger.println("\tNone"); }
+
+ // Print the SSP clusters and populate their distribution graphs.
+ OutputLogger.println("SSP Clusters:");
+ if(!sspClusters.isEmpty()) {
+ for(SSPCluster sspCluster : sspClusters) {
+ OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(sspCluster));
+ }
+ } else { OutputLogger.println("\tNone"); }
+
+ // Print the matched clusters.
+ OutputLogger.println("Matched Clusters:");
+ if(event.getMatchedPairs().size() != 0) {
+ // Iterate over the matched pairs.
+ for(ClusterMatchedPair pair : event.getMatchedPairs()) {
+ // If the pair is a match, print it out.
+ if(pair.isMatch()) {
+ OutputLogger.printf("\t%s --> %s%n",
+ TriggerDiagnosticUtil.clusterToString(pair.getReconstructedCluster()),
+ TriggerDiagnosticUtil.clusterToString(pair.getSSPCluster()));
+ }
+ }
+ }
+ else { OutputLogger.println("\tNone"); }
+
+ // Get the number of position failures.
+ int failPosition = event.getPositionFailures();
+ if(sspClusters == null || sspClusters.isEmpty()) {
+ failPosition = (reconClusters == null ? 0 : reconClusters.size());
+ }
+
+ // Print event statistics.
+ OutputLogger.println();
+ OutputLogger.println("Event Statistics:");
+ OutputLogger.printf("\tRecon Clusters :: %d%n", reconClusters.size());
+ OutputLogger.printf("\tClusters Matched :: %d%n", event.getMatches());
+ OutputLogger.printf("\tFailed (Position) :: %d%n", failPosition);
+ OutputLogger.printf("\tFailed (Energy) :: %d%n", event.getEnergyFailures());
+ OutputLogger.printf("\tFailed (Hit Count) :: %d%n", event.getHitCountFailures());
+ OutputLogger.printf("\tCluster Efficiency :: %3.0f%%%n", 100.0 * event.getMatches() / reconClusters.size());
+
+ // Note whether there was a cluster match failure.
+ if(event.getMatches() - reconClusters.size() != 0) {
+ clusterFail = true;
+ }
+ }
+
+ /**
+ * Checks triggers simulated on SSP clusters against the SSP bank's
+ * reported triggers to verify that the trigger is correctly applying
+ * cuts to the clusters it sees. Additionally compares triggers
+ * simulated on reconstructed clusters to measure trigger efficiency.
+ */
+ private void singlesTriggerVerification() {
+ // Create lists of generic triggers.
+ List<List<? extends Trigger<?>>> sspTriggerList = new ArrayList<List<? extends Trigger<?>>>(2);
+ List<List<? extends Trigger<?>>> reconTriggerList = new ArrayList<List<? extends Trigger<?>>>(2);
+
+ // Convert the simulated triggers to generic versions and add
+ // them to the generic list.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ // Get the generic trigger list.
+ List<? extends Trigger<?>> sspTriggers = sspSinglesTriggers.get(triggerNum);
+ List<? extends Trigger<?>> reconTriggers = reconSinglesTriggers.get(triggerNum);
+
+ // Add it to the generic list.
+ sspTriggerList.add(sspTriggers);
+ reconTriggerList.add(reconTriggers);
+ }
+
+ // Run generic trigger verification.
+ triggerVerification(sspTriggerList, reconTriggerList, true);
+ }
+
+ /**
+ * Checks triggers simulated on SSP clusters against the SSP bank's
+ * reported triggers to verify that the trigger is correctly applying
+ * cuts to the clusters it sees. Additionally compares triggers
+ * simulated on reconstructed clusters to measure trigger efficiency.
+ */
+ private void pairTriggerVerification() {
+ // Create lists of generic triggers.
+ List<List<? extends Trigger<?>>> sspTriggerList = new ArrayList<List<? extends Trigger<?>>>(2);
+ List<List<? extends Trigger<?>>> reconTriggerList = new ArrayList<List<? extends Trigger<?>>>(2);
+
+ // Convert the simulated triggers to generic versions and add
+ // them to the generic list.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ // Get the generic trigger list.
+ List<? extends Trigger<?>> sspTriggers = sspPairsTriggers.get(triggerNum);
+ List<? extends Trigger<?>> reconTriggers = reconPairsTriggers.get(triggerNum);
+
+ // Add it to the generic list.
+ sspTriggerList.add(sspTriggers);
+ reconTriggerList.add(reconTriggers);
+ }
+
+ // Run generic trigger verification.
+ triggerVerification(sspTriggerList, reconTriggerList, false);
+ }
+
+ /**
+ * Performs trigger verification for both trigger types.
+ * @param sspTriggerList - The list of SSP triggers.
+ * @param reconTriggerList - The list of reconstructed triggers.
+ * @param isSingles - Whether or not this is a singles trigger
+ * verification.
+ */
+ private void triggerVerification(List<List<? extends Trigger<?>>> sspTriggerList,
+ List<List<? extends Trigger<?>>> reconTriggerList, boolean isSingles) {
+
+ // ==========================================================
+ // ==== Initialize Trigger Verification =====================
+ // ==========================================================
+
+ // Print the cluster verification header.
+ OutputLogger.println();
+ OutputLogger.println();
+ OutputLogger.println("======================================================================");
+ if(isSingles) { OutputLogger.println("=== Singles Trigger Verification ====================================="); }
+ else { OutputLogger.println("=== Pair Trigger Verification ========================================"); }
+ OutputLogger.println("======================================================================");
+
+ // Track the number of triggers seen and the number found.
+ TriggerMatchEvent event = new TriggerMatchEvent();
+
+ // ==========================================================
+ // ==== Output Event Summary ================================
+ // ==========================================================
+
+ // Get the list of triggers reported by the SSP.
+ List<? extends SSPNumberedTrigger> sspTriggers;
+ if(isSingles) { sspTriggers = sspBank.getSinglesTriggers(); }
+ else { sspTriggers = sspBank.getPairTriggers(); }
+
+ // Output the SSP cluster singles triggers.
+ OutputLogger.println();
+ OutputLogger.println("SSP Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers");
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
+ OutputLogger.printf("\tTrigger %d :: %s :: %s%n",
+ (triggerNum + 1), triggerPositionString(simTrigger),
+ simTrigger.toString());
+ }
+ }
+ if(sspTriggerList.get(0).size() + sspTriggerList.get(1).size() == 0) {
+ OutputLogger.println("\tNone");
+ }
+
+ // Output the reconstructed cluster singles triggers.
+ OutputLogger.println("Reconstructed Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers");
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) {
+ OutputLogger.printf("\tTrigger %d :: %s :: %s%n",
+ (triggerNum + 1), triggerPositionString(simTrigger),
+ simTrigger.toString());
+ }
+ }
+ if(reconTriggerList.get(0).size() + reconTriggerList.get(1).size() == 0) {
+ OutputLogger.println("\tNone");
+ }
+
+ // Output the SSP reported triggers.
+ OutputLogger.println("SSP Reported " + (isSingles ? "Singles" : "Pair") + " Triggers");
+ for(SSPTrigger sspTrigger : sspTriggers) {
+ OutputLogger.printf("\t%s%n", sspTrigger.toString());
+ }
+ if(sspTriggers.size() == 0) { OutputLogger.println("\tNone"); }
+
+
+
+ // ==========================================================
+ // ==== SSP Internal Logic Verification =====================
+ // ==========================================================
+
+ // Track which SSP triggers have been matched to avoid matching
+ // multiple reconstructed SSP cluster triggers to the same SSP
+ // trigger.
+ Set<SSPNumberedTrigger> sspTriggerSet = new HashSet<SSPNumberedTrigger>();
+ Set<Trigger<?>> simTriggerSet = new HashSet<Trigger<?>>();
+
+ // Track the number of SSP reported triggers that are found in
+ // excess of the SSP simulated triggers.
+ int sspReportedExtras = sspTriggers.size() - (sspTriggerList.get(0).size() + sspTriggerList.get(1).size());
+ if(sspReportedExtras > 0) {
+ if(isSingles) { singlesInternalFail = true; }
+ else { pairInternalFail = true; }
+ }
+
+ // Iterate over the triggers.
+ OutputLogger.println();
+ OutputLogger.println("SSP Reported Trigger --> SSP Cluster Trigger Match Status");
+ for(SSPNumberedTrigger sspTrigger : sspTriggers) {
+ // Get the trigger information.
+ int triggerNum = sspTrigger.isFirstTrigger() ? 0 : 1;
+ boolean matchedTrigger = false;
+
+ // Iterate over the SSP cluster simulated triggers and
+ // look for a trigger that matches.
+ matchLoop:
+ for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
+ // If the current SSP trigger has already been
+ // matched, skip it.
+ if(sspTriggerSet.contains(sspTrigger)) { continue matchLoop; }
+
+ // Otherwise, check whether the reconstructed SSP
+ // cluster trigger matches the SSP trigger.
+ if(compareTriggers(sspTrigger, simTrigger)) {
+ matchedTrigger = true;
+ sspTriggerSet.add(sspTrigger);
+ simTriggerSet.add(simTrigger);
+ event.matchedSSPPair(simTrigger, sspTrigger);
+ break matchLoop;
+ }
+
+ OutputLogger.printf("\t%s :: Matched: %5b%n", sspTrigger.toString(), matchedTrigger);
+ }
+ }
+
+ // Iterate over the unmatched simulated triggers again and the
+ // unmatched SSP reported trigger that most closely matches it.
+ simLoop:
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
+ // Check whether this trigger has already been matched
+ // or not. If it has been matched, skip it.
+ if(simTriggerSet.contains(simTrigger)) { continue simLoop; }
+
+ // Get the trigger time for the simulated trigger.
+ double simTime = getTriggerTime(simTrigger);
+
+ // Track the match statistics for each reported trigger
+ // so that the closest match may be found.
+ int numMatched = -1;
+ boolean[] matchedCut = null;
+ SSPNumberedTrigger bestMatch = null;
+
+ // Iterate over the reported triggers to find a match.
+ reportedLoop:
+ for(SSPNumberedTrigger sspTrigger : sspTriggers) {
+ // If the two triggers have different times, this
+ // trigger should be skipped.
+ if(sspTrigger.getTime() != simTime) {
+ continue reportedLoop;
+ }
+
+ // If this reported trigger has been matched then
+ // it should be skipped.
+ if(sspTriggerSet.contains(sspTrigger)) { continue reportedLoop; }
+
+ // Check each of the cuts.
+ boolean[] tempMatchedCut = triggerCutMatch(simTrigger, sspTrigger);
+
+ // Check each cut and see if this is a closer match
+ // than the previous best match.
+ int tempNumMatched = 0;
+ for(boolean passed : tempMatchedCut) { if(passed) { tempNumMatched++; } }
+
+ // If the number of matched cuts exceeds the old
+ // best result, this becomes the new best result.
+ if(tempNumMatched > numMatched) {
+ numMatched = tempNumMatched;
+ matchedCut = tempMatchedCut;
+ bestMatch = sspTrigger;
+ }
+ }
+
+ // If there was no match found, it means that there were
+ // no triggers that were both unmatched and at the same
+ // time as this simulated trigger.
+
+ if(bestMatch == null) {
+ if(isSingles) { singlesInternalFail = true; }
+ else { pairInternalFail = true; }
+ } else {
+ event.matchedSSPPair(simTrigger, bestMatch, matchedCut);
+ }
+ }
+ }
+
+
+
+ // ==========================================================
+ // ==== Trigger Efficiency ==================================
+ // ==========================================================
+
+ // Reset the SSP matched trigger set.
+ sspTriggerSet.clear();
+
+ // Iterate over the reconstructed cluster singles triggers.
+ OutputLogger.println();
+ OutputLogger.println("Recon Cluster Trigger --> SSP Reported Trigger Match Status");
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) {
+
+ OutputLogger.printf("\tTrigger %d :: %s :: %s%n", (triggerNum + 1),
+ triggerPositionString(simTrigger), simTrigger.toString());
+
+ // Iterate over the SSP reported triggers and compare
+ // them to the reconstructed cluster simulated trigger.
+ matchLoop:
+ for(SSPNumberedTrigger sspTrigger : sspTriggers) {
+ OutputLogger.printf("\t\t\t%s", sspTrigger.toString());
+
+ // Only compare triggers if they are from the
+ // same trigger source.
+ if((triggerNum == 0 && sspTrigger.isSecondTrigger())
+ || (triggerNum == 1 && sspTrigger.isFirstTrigger())) {
+ OutputLogger.print(" [ fail; source ]%n");
+ continue matchLoop;
+ }
+
+ // Only compare the singles trigger if it was
+ // not already matched to another trigger.
+ if(sspTriggerSet.contains(sspTrigger)) {
+ OutputLogger.print(" [ fail; matched ]%n");
+ continue matchLoop;
+ }
+
+ // Test each cut.
+ String[][] cutNames = {
+ { "E_min", "E_max", "hit count", "null" },
+ { "E_sum", "E_diff", "E_slope", "coplanar" }
+ };
+ int typeIndex = isSingles ? 0 : 1;
+ boolean[] matchedCuts = triggerCutMatch(simTrigger, sspTrigger);
+ for(int cutIndex = 0; cutIndex < matchedCuts.length; cutIndex++) {
+ if(!matchedCuts[cutIndex]) {
+ OutputLogger.printf(" [ fail; %-9s ]%n", cutNames[typeIndex][cutIndex]);
+ continue matchLoop;
+ }
+ }
+
+ // If all the trigger flags match, then the
+ // triggers are a match.
+ sspTriggerSet.add(sspTrigger);
+ event.matchedReconPair(simTrigger, sspTrigger);
+ OutputLogger.print(" [ success ]%n");
+ break matchLoop;
+ }
+ }
+ }
+
+
+
+ // ==========================================================
+ // ==== Output Event Results ================================
+ // ==========================================================
+
+ // Get the number of SSP and reconstructed cluster simulated
+ // triggers.
+
+ int sspSimTriggers = sspTriggerList.get(0).size() + sspTriggerList.get(1).size();
+ int reconSimTriggers = reconTriggerList.get(0).size() + reconTriggerList.get(1).size();
+ int halfSimTriggers = sspSimTriggers / 2;
+
+ // Print event statistics.
+ OutputLogger.println();
+ OutputLogger.println("Event Statistics:");
+ 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));
+ }
+
+ // Print the individual cut performances.
+ if(isSingles) {
+ OutputLogger.println();
+ 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), halfSimTriggers);
+ OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MAX), halfSimTriggers);
+ OutputLogger.printf("\tCluster Hit Count :: %d / %d%n", event.getCutFailures(triggerNum, HIT_COUNT), halfSimTriggers);
+ } else {
+ OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, ENERGY_MIN), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_MIN) / halfSimTriggers));
+ OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, ENERGY_MAX), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_MAX) / halfSimTriggers));
+ OutputLogger.printf("\tCluster Hit Count :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, HIT_COUNT), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, HIT_COUNT) / halfSimTriggers));
+ }
+ OutputLogger.printf("\tExcess Reported Triggers :: %d%n", sspReportedExtras / 2);
+ }
+
+ // Update the global trigger tracking variables.
+ triggerRunStats[0].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
+ triggerLocalStats[0].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
+ efficiencyRunStats.addSinglesTriggers(activeTrigger, reconTriggerList);
+ efficiencyLocalStats.addSinglesTriggers(activeTrigger, reconTriggerList);
+ efficiencyRunStats.addEvent(activeTrigger, event);
+ efficiencyLocalStats.addEvent(activeTrigger, event);
+ } else {
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ OutputLogger.println();
+ OutputLogger.printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
+ if(sspSimTriggers == 0) {
+ OutputLogger.printf("\tPair Energy Sum :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SUM), halfSimTriggers);
+ OutputLogger.printf("\tPair Energy Difference :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_DIFF), halfSimTriggers);
+ OutputLogger.printf("\tPair Energy Slope :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SLOPE), halfSimTriggers);
+ OutputLogger.printf("\tPair Coplanarity :: %d / %d%n", event.getCutFailures(triggerNum, COPLANARITY), halfSimTriggers);
+ } else {
+ OutputLogger.printf("\tPair Energy Sum :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, ENERGY_SUM), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_SUM) / halfSimTriggers));
+ OutputLogger.printf("\tPair Energy Difference :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, ENERGY_DIFF), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_DIFF) / halfSimTriggers));
+ OutputLogger.printf("\tPair Energy Slope :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, ENERGY_SLOPE), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_SLOPE) / halfSimTriggers));
+ OutputLogger.printf("\tPair Coplanarity :: %d / %d (%3.0f%%)%n",
+ event.getCutFailures(triggerNum, COPLANARITY), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, COPLANARITY) / halfSimTriggers));
+ }
+ OutputLogger.printf("\tExcess Reported Triggers :: %d%n", sspReportedExtras / 2);
+ }
+
+ // Update the global trigger tracking variables.
+ triggerRunStats[1].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
+ triggerLocalStats[1].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
+ efficiencyRunStats.addPairTriggers(activeTrigger, reconTriggerList);
+ efficiencyLocalStats.addSinglesTriggers(activeTrigger, reconTriggerList);
+ efficiencyRunStats.addEvent(activeTrigger, event);
+ efficiencyLocalStats.addEvent(activeTrigger, event);
+ }
+
+ // Note whether the was a trigger match failure.
+ if((event.getMatchedReconTriggers() - reconSimTriggers != 0) || (event.getMatchedSSPTriggers() - sspSimTriggers != 0)) {
+ if(isSingles) { singlesEfficiencyFail = true; }
+ else { pairEfficiencyFail = true; }
+ }
+ }
+
+ /**
+ * Generates and stores the singles triggers for both reconstructed
+ * and SSP clusters.
+ */
+ private void constructSinglesTriggers() {
+ // Run the SSP clusters through the singles trigger to determine
+ // whether they pass it or not.
+ for(SSPCluster cluster : sspClusters) {
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ // For a cluster to have formed it is assumed to have passed
+ // the cluster seed energy cuts. This can not be verified
+ // since the SSP bank does not report individual hit.
+ boolean passSeedLow = true;
+ boolean passSeedHigh = true;
+
+ // The remaining cuts may be acquired from trigger module.
+ boolean passClusterLow = singlesTrigger[triggerNum].clusterTotalEnergyCutLow(cluster);
+ boolean passClusterHigh = singlesTrigger[triggerNum].clusterTotalEnergyCutHigh(cluster);
+ boolean passHitCount = singlesTrigger[triggerNum].clusterHitCountCut(cluster);
+
+ // Make a trigger to store the results.
+ SinglesTrigger<SSPCluster> trigger = new SinglesTrigger<SSPCluster>(cluster, triggerNum);
+ trigger.setStateSeedEnergyLow(passSeedLow);
+ trigger.setStateSeedEnergyHigh(passSeedHigh);
+ trigger.setStateClusterEnergyLow(passClusterLow);
+ trigger.setStateClusterEnergyHigh(passClusterHigh);
+ trigger.setStateHitCount(passHitCount);
+
+ // Store the trigger.
+ sspSinglesTriggers.get(triggerNum).add(trigger);
+ }
+ }
+
+ // Run the reconstructed clusters through the singles trigger
+ // to determine whether they pass it or not.
+ for(Cluster cluster : reconClusters) {
+ // Simulate each of the cluster singles triggers.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ // For a cluster to have formed it is assumed to have passed
+ // the cluster seed energy cuts. This can not be verified
+ // since the SSP bank does not report individual hit.
+ boolean passSeedLow = true;
+ boolean passSeedHigh = true;
+
+ // The remaining cuts may be acquired from trigger module.
+ boolean passClusterLow = singlesTrigger[triggerNum].clusterTotalEnergyCutLow(cluster);
+ boolean passClusterHigh = singlesTrigger[triggerNum].clusterTotalEnergyCutHigh(cluster);
+ boolean passHitCount = singlesTrigger[triggerNum].clusterHitCountCut(cluster);
+
+ // Make a trigger to store the results.
+ SinglesTrigger<Cluster> trigger = new SinglesTrigger<Cluster>(cluster, triggerNum);
+ trigger.setStateSeedEnergyLow(passSeedLow);
+ trigger.setStateSeedEnergyHigh(passSeedHigh);
+ trigger.setStateClusterEnergyLow(passClusterLow);
+ trigger.setStateClusterEnergyHigh(passClusterHigh);
+ trigger.setStateHitCount(passHitCount);
+
+ // Store the trigger.
+ reconSinglesTriggers.get(triggerNum).add(trigger);
+ }
+ }
+ }
+
+ /**
+ * Generates and stores the pair triggers for both reconstructed
+ * and SSP clusters.
+ */
+ private void constructPairTriggers() {
+ // Store cluster pairs.
+ List<Cluster> topReconClusters = new ArrayList<Cluster>();
+ List<Cluster> bottomReconClusters = new ArrayList<Cluster>();
+ List<Cluster[]> reconPairs = new ArrayList<Cluster[]>();
+ List<SSPCluster> topSSPClusters = new ArrayList<SSPCluster>();
+ List<SSPCluster> bottomSSPClusters = new ArrayList<SSPCluster>();
+ List<SSPCluster[]> sspPairs = new ArrayList<SSPCluster[]>();
+
+ // Split the clusters into lists of top and bottom clusters.
+ for(Cluster reconCluster : reconClusters) {
+ if(reconCluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy") > 0) {
+ topReconClusters.add(reconCluster);
+ } else {
+ bottomReconClusters.add(reconCluster);
+ }
+ }
+ for(SSPCluster sspCluster : sspClusters) {
+ if(sspCluster.getYIndex() > 0) {
+ topSSPClusters.add(sspCluster);
+ } else {
+ bottomSSPClusters.add(sspCluster);
+ }
+ }
+
+ // Form all possible top/bottom cluster pairs.
+ for(Cluster topReconCluster : topReconClusters) {
+ for(Cluster bottomReconCluster : bottomReconClusters) {
+ Cluster[] reconPair = new Cluster[2];
+ reconPair[0] = topReconCluster;
+ reconPair[1] = bottomReconCluster;
+ reconPairs.add(reconPair);
+ }
+ }
+ for(SSPCluster topSSPCluster : topSSPClusters) {
+ for(SSPCluster bottomSSPCluster : bottomSSPClusters) {
+ SSPCluster[] sspPair = new SSPCluster[2];
+ sspPair[0] = topSSPCluster;
+ sspPair[1] = bottomSSPCluster;
+ sspPairs.add(sspPair);
+ }
+ }
+
+ // Simulate the pair triggers and record the results.
+ for(Cluster[] reconPair : reconPairs) {
+ // Simulate each of the cluster pair triggers.
+ reconTriggerLoop:
+ for(int triggerIndex = 0; triggerIndex < 2; triggerIndex++) {
+ // Check that the pair passes the time coincidence cut.
+ // If it does not, it is not a valid pair and should be
+ // destroyed.
+ if(!pairsTrigger[triggerIndex].pairTimeCoincidenceCut(reconPair)) {
+ continue reconTriggerLoop;
+ }
+
+ // For a cluster to have formed it is assumed to have passed
+ // the cluster seed energy cuts. This can not be verified
+ // since the SSP bank does not report individual hit.
+ boolean passSeedLow = true;
+ boolean passSeedHigh = true;
+
+ // The remaining cuts may be acquired from trigger module.
+ boolean passClusterLow = pairsTrigger[triggerIndex].clusterTotalEnergyCutLow(reconPair[0])
+ && pairsTrigger[triggerIndex].clusterTotalEnergyCutLow(reconPair[1]);
+ boolean passClusterHigh = pairsTrigger[triggerIndex].clusterTotalEnergyCutHigh(reconPair[0])
+ && pairsTrigger[triggerIndex].clusterTotalEnergyCutHigh(reconPair[1]);
+ boolean passHitCount = pairsTrigger[triggerIndex].clusterHitCountCut(reconPair[0])
+ && pairsTrigger[triggerIndex].clusterHitCountCut(reconPair[1]);
+ boolean passPairEnergySumLow = pairsTrigger[triggerIndex].pairEnergySumCutLow(reconPair);
+ boolean passPairEnergySumHigh = pairsTrigger[triggerIndex].pairEnergySumCutHigh(reconPair);
+ boolean passPairEnergyDifference = pairsTrigger[triggerIndex].pairEnergyDifferenceCut(reconPair);
+ boolean passPairEnergySlope = pairsTrigger[triggerIndex].pairEnergySlopeCut(reconPair);
+ boolean passPairCoplanarity = pairsTrigger[triggerIndex].pairCoplanarityCut(reconPair);
+ boolean passTimeCoincidence = pairsTrigger[triggerIndex].pairTimeCoincidenceCut(reconPair);
+
+ // Create a trigger from the results.
+ PairTrigger<Cluster[]> trigger = new PairTrigger<Cluster[]>(reconPair, triggerIndex);
+ trigger.setStateSeedEnergyLow(passSeedLow);
+ trigger.setStateSeedEnergyHigh(passSeedHigh);
+ trigger.setStateClusterEnergyLow(passClusterLow);
+ trigger.setStateClusterEnergyHigh(passClusterHigh);
+ trigger.setStateHitCount(passHitCount);
+ trigger.setStateEnergySumLow(passPairEnergySumLow);
+ trigger.setStateEnergySumHigh(passPairEnergySumHigh);
+ trigger.setStateEnergyDifference(passPairEnergyDifference);
+ trigger.setStateEnergySlope(passPairEnergySlope);
+ trigger.setStateCoplanarity(passPairCoplanarity);
+ trigger.setStateTimeCoincidence(passTimeCoincidence);
+
+ // Add the trigger to the list.
+ reconPairsTriggers.get(triggerIndex).add(trigger);
+ }
+ }
+
+ for(SSPCluster[] sspPair : sspPairs) {
+ pairTriggerLoop:
+ for(int triggerIndex = 0; triggerIndex < 2; triggerIndex++) {
+ // Check that the pair passes the time coincidence cut.
+ // If it does not, it is not a valid pair and should be
+ // destroyed.
+ if(!pairsTrigger[triggerIndex].pairTimeCoincidenceCut(sspPair)) {
+ continue pairTriggerLoop;
+ }
+
+ // For a cluster to have formed it is assumed to have passed
+ // the cluster seed energy cuts. This can not be verified
+ // since the SSP bank does not report individual hit.
+ boolean passSeedLow = true;
+ boolean passSeedHigh = true;
+
+ // The remaining cuts may be acquired from trigger module.
+ boolean passClusterLow = pairsTrigger[triggerIndex].clusterTotalEnergyCutLow(sspPair[0])
+ && pairsTrigger[triggerIndex].clusterTotalEnergyCutLow(sspPair[1]);
+ boolean passClusterHigh = pairsTrigger[triggerIndex].clusterTotalEnergyCutHigh(sspPair[0])
+ && pairsTrigger[triggerIndex].clusterTotalEnergyCutHigh(sspPair[1]);
+ boolean passHitCount = pairsTrigger[triggerIndex].clusterHitCountCut(sspPair[0])
+ && pairsTrigger[triggerIndex].clusterHitCountCut(sspPair[1]);
+ boolean passPairEnergySumLow = pairsTrigger[triggerIndex].pairEnergySumCutLow(sspPair);
+ boolean passPairEnergySumHigh = pairsTrigger[triggerIndex].pairEnergySumCutHigh(sspPair);
+ boolean passPairEnergyDifference = pairsTrigger[triggerIndex].pairEnergyDifferenceCut(sspPair);
+ boolean passPairEnergySlope = pairsTrigger[triggerIndex].pairEnergySlopeCut(sspPair);
+ boolean passPairCoplanarity = pairsTrigger[triggerIndex].pairCoplanarityCut(sspPair);
+ boolean passTimeCoincidence = pairsTrigger[triggerIndex].pairTimeCoincidenceCut(sspPair);
+
+ // Create a trigger from the results.
+ PairTrigger<SSPCluster[]> trigger = new PairTrigger<SSPCluster[]>(sspPair, triggerIndex);
+ trigger.setStateSeedEnergyLow(passSeedLow);
+ trigger.setStateSeedEnergyHigh(passSeedHigh);
+ trigger.setStateClusterEnergyLow(passClusterLow);
+ trigger.setStateClusterEnergyHigh(passClusterHigh);
+ trigger.setStateHitCount(passHitCount);
+ trigger.setStateEnergySumLow(passPairEnergySumLow);
+ trigger.setStateEnergySumHigh(passPairEnergySumHigh);
+ trigger.setStateEnergyDifference(passPairEnergyDifference);
+ trigger.setStateEnergySlope(passPairEnergySlope);
+ trigger.setStateCoplanarity(passPairCoplanarity);
+ trigger.setStateTimeCoincidence(passTimeCoincidence);
+
+ // Add the trigger to the list.
+ sspPairsTriggers.get(triggerIndex).add(trigger);
+ }
+ }
+ }
+
+ /**
+ * Outputs all of the verification parameters currently in use by
+ * the software. A warning will be issued if the values for NSA and
+ * NSB, along with the FADC window, preclude clusters from being
+ * verified.
+ */
+ private void logSettings() {
+ // Output general settings.
+ System.out.println("Cluster Verification Settings");
+ System.out.printf("\tEnergy Threshold :: %1.2f%%%n", energyAcceptance);
+ System.out.printf("\tHit Threshold :: %1d%n", hitAcceptance);
+
+ // Output window settings.
+ System.out.println("FADC Timing Window Settings");
+ System.out.printf("\tNSB :: %3d ns%n", nsb);
+ System.out.printf("\tNSA :: %3d ns%n", nsa);
+ System.out.printf("\tFADC Window :: %3d ns%n", windowWidth);
+
+ // Calculate the valid clustering window.
+ int start = nsb;
+ int end = windowWidth - nsa;
+ if(start < end) {
+ System.out.printf("\tValid Cluster Window :: [ %3d ns, %3d ns ]%n", start, end);
+ performClusterVerification = true;
+ } else {
+ System.out.println("\tNSB, NSA, and FADC window preclude a valid cluster verification window.");
+ System.out.println("\tCluster verification will not be performed!");
+ performClusterVerification = false;
+ }
+
+ // Output the singles trigger settings.
+ for(int i = 0; i < 2; i++) {
+ System.out.printf("Singles Trigger %d Settings%n", (i + 1));
+ System.out.printf("\tCluster Energy Low :: %.3f GeV%n", singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW));
+ System.out.printf("\tCluster Energy High :: %.3f GeV%n", singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH));
+ System.out.printf("\tCluster Hit Count :: %.0f hits%n", singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW));
+ }
+
+ // Output the pair trigger settings.
+ for(int i = 0; i < 2; i++) {
+ System.out.printf("Pairs Trigger %d Settings%n", (i + 1));
+ System.out.printf("\tCluster Energy Low :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW));
+ System.out.printf("\tCluster Energy High :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH));
+ System.out.printf("\tCluster Hit Count :: %.0f hits%n", pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW));
+ System.out.printf("\tPair Energy Sum Low :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW));
+ System.out.printf("\tPair Energy Sum Low :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH));
+ System.out.printf("\tPair Energy Difference :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH));
+ System.out.printf("\tPair Energy Slope :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW));
+ System.out.printf("\tPair Energy Slope F :: %.3f GeV / mm%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F));
+ System.out.printf("\tPair Coplanarity :: %.0f Degrees%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_COPLANARITY_HIGH));
+ System.out.printf("\tPair Time Coincidence :: %.0f ns%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_TIME_COINCIDENCE));
+ }
+ }
+
+ /**
+ * Checks whether all of the hits in a cluster are within the safe
+ * region of the FADC output window.
+ * @param reconCluster - The cluster to check.
+ * @return Returns <code>true</code> if the cluster is safe and
+ * returns <code>false</code> otherwise.
+ */
+ private final boolean isVerifiable(Cluster reconCluster) {
+ return TriggerDiagnosticUtil.isVerifiable(reconCluster, nsa, nsb, windowWidth);
+ }
+
+ /**
+ * Compares an SSP trigger with a simulated trigger. Note that only
+ * certain class combinations are supported. Triggers of the type
+ * <code>SSPSinglesTrigger</code> may be compared with triggers of
+ * the type <code>SinglesTrigger<SSPCluster></code> and triggers of
+ * the type <code>SSPPairTrigger</code> may be compared to either
+ * <code>PairTrigger<SSPCluster[]></code> triggers objects.
+ * @param bankTrigger - The SSP bank trigger.
+ * @param simTrigger - The simulated trigger.
+ * @return Returns <code>true</code> if the triggers are valid
+ * matches and <code>false</code> if they are not.
+ * @throws IllegalArgumentException Occurs if the trigger types
+ * are not of a supported type.
+ */
+ @SuppressWarnings("unchecked")
+ private static final boolean compareTriggers(SSPNumberedTrigger bankTrigger, Trigger<?> simTrigger) throws IllegalArgumentException {
+ // Get the classes of the arguments. This is used to check the
+ // generic type of the Trigger<?> object, and means that the
+ // "unchecked" warnings can be safely ignored.
+ Object source = simTrigger.getTriggerSource();
+
+ // If the combination of classes is supported, pass the triggers
+ // to the appropriate handler.
+ if(bankTrigger instanceof SSPSinglesTrigger && simTrigger instanceof SinglesTrigger && source instanceof SSPCluster) {
+ return compareSSPSinglesTriggers((SSPSinglesTrigger) bankTrigger, (SinglesTrigger<SSPCluster>) simTrigger);
+ } else if(bankTrigger instanceof SSPPairTrigger && simTrigger instanceof PairTrigger && source instanceof SSPCluster[]) {
+ return compareSSPPairTriggers((SSPPairTrigger) bankTrigger, (PairTrigger<SSPCluster[]>) simTrigger);
+ }
+
+ // Otherwise, the trigger combination is not supported. Produce
+ // and exception.
+ throw new IllegalArgumentException(String.format("Trigger type \"%s\" can not be compared to trigger type \"%s\" with source type \"%s\".",
+ bankTrigger.getClass().getSimpleName(), simTrigger.getClass().getSimpleName(), source.getClass().getSimpleName()));
+ }
+
+ /**
+ * Compares a trigger from the SSP bank to a trigger simulated on
+ * an SSP cluster.
+ * @param bankTrigger - The trigger from the SSP bank.
+ * @param simTrigger - The trigger from the simulation.
+ * @return Returns <code>true</code> if the triggers match and
+ * <code>false</code> if they do not.
+ */
+ private static final boolean compareSSPSinglesTriggers(SSPSinglesTrigger bankTrigger, SinglesTrigger<SSPCluster> simTrigger) {
+ // The bank trigger and simulated trigger must have the same
+ // time. This is equivalent to the time of the triggering cluster.
+ if(bankTrigger.getTime() != simTrigger.getTriggerSource().getTime()) {
+ return false;
+ }
+
+ // If the time stamp is the same, check that the trigger flags
+ // are all the same. Start with cluster energy low.
+ if(bankTrigger.passCutEnergyMin() != simTrigger.getStateClusterEnergyLow()) {
+ return false;
+ }
+
+ // Check cluster energy high.
+ if(bankTrigger.passCutEnergyMax() != simTrigger.getStateClusterEnergyHigh()) {
+ return false;
+ }
+
+ // Check cluster hit count.
+ if(bankTrigger.passCutHitCount() != simTrigger.getStateHitCount()) {
+ return false;
+ }
+
+ // If all of the tests are successful, the triggers match.
+ return true;
+ }
+
+ /**
+ * Compares a trigger from the SSP bank to a trigger simulated on
+ * an SSP cluster.
+ * @param bankTrigger - The trigger from the SSP bank.
+ * @param simTrigger - The trigger from the simulation.
+ * @return Returns <code>true</code> if the triggers match and
+ * <code>false</code> if they do not.
+ */
+ private static final boolean compareSSPPairTriggers(SSPPairTrigger bankTrigger, PairTrigger<SSPCluster[]> simTrigger) {
+ // Get the time of the bottom cluster in the pair.
+ int simTime = 0;
+ if(simTrigger.getTriggerSource()[0].getYIndex() < 0) {
+ simTime = simTrigger.getTriggerSource()[0].getTime();
+ } else {
+ simTime = simTrigger.getTriggerSource()[1].getTime();
+ }
+
+ // The bank trigger and simulated trigger must have the same
+ // time. This is equivalent to the time of the triggering cluster.
+ if(bankTrigger.getTime() != simTime) { return false; }
+
+ // If the time stamp is the same, check that the trigger flags
+ // are all the same. Start with energy sum.
+ if(bankTrigger.passCutEnergySum() != simTrigger.getStateEnergySum()) {
+ return false;
+ }
+
+ // Check pair energy difference.
+ if(bankTrigger.passCutEnergyDifference() != simTrigger.getStateEnergyDifference()) {
+ return false;
+ }
+
+ // Check pair energy slope.
+ if(bankTrigger.passCutEnergySlope() != simTrigger.getStateEnergySlope()) {
+ return false;
+ }
+
+ // Check pair coplanarity.
+ if(bankTrigger.passCutCoplanarity() != simTrigger.getStateCoplanarity()) {
+ return false;
+ }
+
+ // If all of the tests are successful, the triggers match.
+ return true;
+ }
+
+ /**
+ * Generates a <code>List</code> collection that contains a set
+ * of <code>ArrayList</code> collections representing a unique
+ * permutation of the entries in the argument.
+ * @param values - A collection of the entries to be permuted.
+ * @return Returns a list of lists representing the permutations.
+ */
+ private static final List<List<Pair<Cluster, SSPCluster>>> getPermutations(List<Cluster> reconClusters, List<SSPCluster> sspClusters) {
+ // Store the SSP cluster permutations.
+ List<List<SSPCluster>> permList = new ArrayList<List<SSPCluster>>();
+
+ // Make sure that the two lists are the same size.
+ int reconSize = reconClusters.size();
+ int sspSize = sspClusters.size();
+ while(sspClusters.size() < reconClusters.size()) {
+ sspClusters.add(null);
+ }
+ while(reconClusters.size() < sspClusters.size()) {
+ reconClusters.add(null);
+ }
+
+ // Get the SSP cluster permutations.
+ permute(new ArrayList<SSPCluster>(0), sspClusters, permList);
+
+ // Create pairs from the permutations.
+ List<List<Pair<Cluster, SSPCluster>>> pairList = new ArrayList<List<Pair<Cluster, SSPCluster>>>();
+ for(List<SSPCluster> permutation : permList) {
+ List<Pair<Cluster, SSPCluster>> pairs = new ArrayList<Pair<Cluster, SSPCluster>>(reconClusters.size());
+
+ for(int clusterIndex = 0; (clusterIndex < reconClusters.size() && clusterIndex < permutation.size()); clusterIndex++) {
+ pairs.add(new Pair<Cluster, SSPCluster>(reconClusters.get(clusterIndex), permutation.get(clusterIndex)));
+ }
+
+ pairList.add(pairs);
+ }
+
+ // Remove the extra values.
+ for(int i = sspClusters.size() - 1; i >= sspSize; i--) { sspClusters.remove(i); }
+ for(int i = reconClusters.size() - 1; i >= reconSize; i--) { reconClusters.remove(i); }
+
+ // Return the pairs.
+ return pairList;
+ }
+
+ /**
+ * Recursive method for permuting all entries in the argument
+ * collection <code>remainingValues</code> into the argument
+ * <code>permutedValues</code> values. Completed permutations are
+ * placed in the argument <code>permList</code>.
+ * @param permutedValues - List to store entries that have already
+ * been permuted.
+ * @param remainingValues - List to store entries that need to be
+ * permuted.
+ * @param permList - List to store completed permutations.
+ */
+ private static final void permute(List<SSPCluster> permutedValues, List<SSPCluster> remainingValues, List<List<SSPCluster>> permList) {
+ // If the list of entries that still need to be sorted is empty,
+ // then there is nothing to sort. Just return and empty list.
+ if(remainingValues.isEmpty()) { return; }
+
+ // If there is only one value left in the list of entries that
+ // still need to be sorted, then just add it to the permutation
+ // list and return it.
+ else if(remainingValues.size() <= 1) {
+ // Add the last entry.
+ permutedValues.add(remainingValues.get(0));
+
+ // Add the permutation to the list of completed permutations.
+ permList.add(permutedValues);
+ }
+
+ // Otherwise, continue to get all possible permutations.
+ else {
+ // Iterate over the entries that have not been permuted.
+ for(int i = 0; i < remainingValues.size(); i++) {
+ // Make new lists to contain the permutations.
+ List<SSPCluster> newPermList = new ArrayList<SSPCluster>(permutedValues.size() + 1);
+ List<SSPCluster> newRemainList = new ArrayList<SSPCluster>(remainingValues.size());
+
+ // Copy the current permuted entries to the new list
+ // and one value from the list of entries that have
+ // not been permuted yet.
+ newPermList.addAll(permutedValues);
+ newPermList.add(remainingValues.get(i));
+
+ // The new list of entries that have not been permuted
+ // should be identical, except it should now be missing
+ // the entry that was moved.
+ for(int index = 0; index < remainingValues.size(); index++) {
+ if(index != i) { newRemainList.add(remainingValues.get(index)); }
+ }
+
+ // Repeat the process with the new lists.
+ permute(newPermList, newRemainList, permList);
+ }
+ }
+ }
+
+ /**
+ * Compares two cluster matching events and finds the one that has
+ * the better results. Note that this will only return results that
+ * make sense if both of the events represent different permutations
+ * of the same set of clusters. Comparing events with different sets
+ * of clusters will produce meaningless results.
+ * @param firstEvent - The first cluster matching event,
+ * @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) {
+ // If both permutations are null, return that.
+ if(firstEvent == null && secondEvent == null) {
+ return null;
+ }
+
+ // If one permutation is null, it is not the best.
+ if(firstEvent == null) { return secondEvent; }
+ else if(secondEvent == null) { return firstEvent; }
+
+ // A permutation is better if it has more matches.
+ if(firstEvent.getMatches() > secondEvent.getMatches()) { return firstEvent; }
+ else if(secondEvent.getMatches() > firstEvent.getMatches()) { return secondEvent; }
+
+ // Otherwise, the permutation with the least energy failures is
+ // the better permutation.
+ if(firstEvent.getEnergyFailures() < secondEvent.getEnergyFailures()) { return firstEvent; }
+ else if(secondEvent.getEnergyFailures() < firstEvent.getEnergyFailures()) { return secondEvent; }
+
+ // If both these values are the same, then the events are identical.
+ return firstEvent;
+ }
+
+ /**
+ * Determines the number of spaces needed to render the longest of
+ * a series of integers as a string.
+ * @param vals - The series of integers.
+ * @return Returns the number of spaces needed to render the longest
+ * integer as a base-10 string.
+ */
+ private static final int getPrintSpaces(int... vals) {
+ // Track the largest value.
+ int largest = 0;
+
+ // Iterate over the arguments and find the largest.
+ for(int val : vals) {
+ // Get the length of the string.
+ int length = TriggerDiagnosticUtil.getDigits(val);
+
+ // If it is larger, track it.
+ if(length > largest) { largest = length; }
+ }
+
+ // Return the longer one.
+ return largest;
+ }
+
+ /**
+ * Gets the position of the source of a <code>Trigger</code> object
+ * as text. This method only supports trigger sources of the types
+ * <code>SSPCluster</code>, <code>Cluster</code>, and arrays of size
+ * two of either type.
+ * @param trigger - The trigger from which to obtain the source.
+ * @return Returns the source of the trigger as a <code>String</code>
+ * object.
+ * @throws IllegalArgumentException Occurs if the source of the
+ * trigger is not any of the supported types.
+ */
+ private static final String triggerPositionString(Trigger<?> trigger) throws IllegalArgumentException {
+ // Get the trigger source.
+ Object source = trigger.getTriggerSource();
+
+ // Handle valid trigger sources.
+ if(source instanceof SSPCluster) {
+ return TriggerDiagnosticUtil.clusterPositionString((SSPCluster) source);
+ } else if(source instanceof Cluster) {
+ return TriggerDiagnosticUtil.clusterPositionString((Cluster) source);
+ } else if(source instanceof SSPCluster[]) {
+ SSPCluster[] sourcePair = (SSPCluster[]) source;
+ if(sourcePair.length == 2) {
+ return String.format("%s, %s", TriggerDiagnosticUtil.clusterPositionString(sourcePair[0]),
+ TriggerDiagnosticUtil.clusterPositionString(sourcePair[1]));
+ }
+ } else if(source instanceof Cluster[]) {
+ Cluster[] sourcePair = (Cluster[]) source;
+ if(sourcePair.length == 2) {
+ return String.format("%s, %s", TriggerDiagnosticUtil.clusterPositionString(sourcePair[0]),
+ TriggerDiagnosticUtil.clusterPositionString(sourcePair[1]));
+ }
+ }
+
+ // Otherwise, the source type is unrecognized. Throw an error.
+ throw new IllegalArgumentException(String.format("Trigger source type \"%s\" is not supported.",
+ trigger.getTriggerSource().getClass().getSimpleName()));
+ }
+
+ /**
+ * Gets the time of a simulated trigger object. Method supports
+ * triggers with source objects of type <code>SSPCluster</code>,
+ * <code>Cluster</code>, and arrays of size two composed of either
+ * object type.
+ * @param trigger - The trigger.
+ * @return Returns the time at which the trigger occurred.
+ * @throws IllegalArgumentException Occurs if the trigger source
+ * is not a supported type.
+ */
+ private static final double getTriggerTime(Trigger<?> trigger) throws IllegalArgumentException {
+ // Get the trigger source.
+ Object source = trigger.getTriggerSource();
+
+ // Get the trigger time for supported trigger types.
+ if(source instanceof SSPCluster) {
+ return ((SSPCluster) source).getTime();
+ } else if(source instanceof Cluster) {
+ return TriggerDiagnosticUtil.getClusterTime((Cluster) source);
+ } else if(source instanceof SSPCluster[]) {
+ // Get the pair.
+ SSPCluster[] sourcePair = (SSPCluster[]) source;
+
+ // Get the time of the bottom cluster.
+ if(sourcePair.length == 2) {
+ if(sourcePair[0].getYIndex() < 0) { return sourcePair[0].getTime(); }
+ else if(sourcePair[1].getYIndex() < 0) { return sourcePair[1].getTime(); }
+ else { throw new IllegalArgumentException("Cluster pairs must be formed of a top/bottom pair."); }
+ }
+ else { throw new IllegalArgumentException("Cluster pairs must be of size 2."); }
+ } else if(source instanceof Cluster[]) {
+ // Get the pair.
+ Cluster[] sourcePair = (Cluster[]) source;
+ int[] iy = {
+ TriggerDiagnosticUtil.getYIndex(sourcePair[0]),
+ TriggerDiagnosticUtil.getYIndex(sourcePair[1])
+ };
+
+ // Get the time of the bottom cluster.
+ if(sourcePair.length == 2) {
+ if(iy[0] < 0) { return TriggerDiagnosticUtil.getClusterTime(sourcePair[0]); }
+ else if(iy[1] < 0) { return TriggerDiagnosticUtil.getClusterTime(sourcePair[1]); }
+ else { throw new IllegalArgumentException("Cluster pairs must be formed of a top/bottom pair."); }
+ }
+ else { throw new IllegalArgumentException("Cluster pairs must be of size 2."); }
+ }
+
+ // If the source type is unrecognized, throw an exception.
+ throw new IllegalArgumentException(String.format("Trigger source type \"%\" is not supported.",
+ source.getClass().getSimpleName()));
+ }
+
+ /**
+ * Checks if a simulated trigger and an SSP trigger match. Note
+ * that only certain types can be compared. These are:
+ * <ul><li><code>SinglesTrigger<?> --> SSPSinglesTrigger</code></li>
+ * <li><code>PairTrigger<?> --> SSPPairTrigger</code></li></ul>
+ * @param simTrigger - The simulated trigger.
+ * @param sspTrigger - The SSP bank trigger.
+ * @return Returns an array of <code>boolean</code> primitives that
+ * indicate which cuts passed and which failed.
+ */
+ private static final boolean[] triggerCutMatch(Trigger<?> simTrigger, SSPTrigger sspTrigger) {
+ // Check that the cuts match for supported trigger types.
+ if(simTrigger instanceof SinglesTrigger && sspTrigger instanceof SSPSinglesTrigger) {
+ // Create an array to store the cut checks.
+ boolean[] cutMatch = new boolean[3];
+
+ // Cast the triggers.
+ SinglesTrigger<?> simSingles = (SinglesTrigger<?>) simTrigger;
+ SSPSinglesTrigger sspSingles = (SSPSinglesTrigger) sspTrigger;
+
+ // Perform the check.
+ cutMatch[ENERGY_MIN] = (simSingles.getStateClusterEnergyLow() == sspSingles.passCutEnergyMin());
+ cutMatch[ENERGY_MAX] = (simSingles.getStateClusterEnergyHigh() == sspSingles.passCutEnergyMax());
+ cutMatch[HIT_COUNT] = (simSingles.getStateHitCount() == sspSingles.passCutHitCount());
+
+ // Return the match array.
+ return cutMatch;
+ } else if(simTrigger instanceof PairTrigger && sspTrigger instanceof SSPPairTrigger) {
+ // Create an array to store the cut checks.
+ boolean[] cutMatch = new boolean[4];
+
+ // Cast the triggers.
+ PairTrigger<?> simPair = (PairTrigger<?>) simTrigger;
+ SSPPairTrigger sspPair = (SSPPairTrigger) sspTrigger;
+
+ // Perform the check.
+ cutMatch[ENERGY_SUM] = (simPair.getStateEnergySum() == sspPair.passCutEnergySum());
+ cutMatch[ENERGY_DIFF] = (simPair.getStateEnergyDifference() == sspPair.passCutEnergyDifference());
+ cutMatch[ENERGY_SLOPE] = (simPair.getStateEnergySlope() == sspPair.passCutEnergySlope());
+ cutMatch[COPLANARITY] = (simPair.getStateCoplanarity() == sspPair.passCutCoplanarity());
+
+ // Return the match array.
+ return cutMatch;
+ }
+
+ // If this point is reached, the triggers are not of a supported
+ // type for cut comparison. Produce an exception.
+ throw new IllegalArgumentException(String.format("Triggers of type \"%s\" can not be cut-matched with triggers of type \"%s\".",
+ simTrigger.getClass().getSimpleName(), sspTrigger.getClass().getSimpleName()));
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,145 @@
+package org.hps.analysis.trigger.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.lcsim.event.Cluster;
+
+/**
+ * Class <code>ClusterMatchEvent</code> tracks reconstructed/SSP cluster
+ * pairs for the purpose of cluster matching. It maintains a list of
+ * all pairs that have been seen as well as their match states. It can
+ * additionally provide the total number of each type of match state.
+ *
+ * @author Kyle McCarty
+ */
+public class ClusterMatchEvent {
+ // Track the number of state instances.
+ private int matched = 0;
+ private int failPosition = 0;
+ private int failEnergy = 0;
+ private int failHitCount = 0;
+
+ // Store all of the pairs.
+ private List<ClusterMatchedPair> pairList = new ArrayList<ClusterMatchedPair>();
+
+ /**
+ * Fuses another <code>ClusterMatchEvent</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(ClusterMatchEvent event) {
+ // If the event is null, do nothing.
+ if(event == null) { return; }
+
+ // Iterate over the new event's matched pairs and add them into
+ // this event's statistics.
+ for(ClusterMatchedPair cmp : event.pairList) {
+ // Add the current pair to this pair list.
+ pairList.add(cmp);
+
+ // Increment the statistics counters based on the pair state.
+ if(cmp.isMatch()) { matched++; }
+ if(cmp.isPositionFailState()) { failPosition++; }
+ if(cmp.isEnergyFailState()) { failEnergy++; }
+ if(cmp.isHitCountFailState()) { failHitCount++; }
+ }
+ }
+
+ /**
+ * 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 match states.
+ * @return Returns the number of instances of this state as an
+ * <code>int</code> primitive.
+ */
+ public List<ClusterMatchedPair> getMatchedPairs() {
+ return pairList;
+ }
+
+ /**
+ * 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 matched;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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) {
+ failEnergy++;
+ 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) {
+ failHitCount++;
+ 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) {
+ failPosition++;
+ pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_POSITION));
+ }
+
+ /**
+ * 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) {
+ matched++;
+ pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_MATCHED));
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,200 @@
+package org.hps.analysis.trigger.event;
+
+import java.awt.Point;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.lcsim.event.Cluster;
+
+/**
+ * Tracks the status of cluster matching for the purposes of trigger
+ * verification.
+ *
+ * @author Kyle McCarty
+ */
+public class ClusterMatchStatus extends ClusterStatModule {
+ // Plot binning values.
+ private static final int TIME_BIN = 4;
+ private static final double ENERGY_BIN = 0.01;
+ private static final int TIME_BIN_HALF = TIME_BIN / 2;
+ private static final double ENERGY_BIN_HALF = ENERGY_BIN / 2;
+
+ // Track plotting values for reconstructed and SSP clusters.
+ private Map<Integer, Integer> sspHitCountBins = new HashMap<Integer, Integer>();
+ private Map<Integer, Integer> reconHitCountBins = new HashMap<Integer, Integer>();
+ private Map<Point, Integer> sspPositionBins = new HashMap<Point, Integer>();
+ private Map<Point, Integer> reconPositionBins = new HashMap<Point, Integer>();
+ private Map<Integer, Integer> sspEnergyBins = new HashMap<Integer, Integer>();
+ private Map<Integer, Integer> reconEnergyBins = new HashMap<Integer, Integer>();
+
+ // Track plotting values for cluster matching results.
+ private Map<Point, Integer> failPositionBins = new HashMap<Point, Integer>();
+ private Map<Point, Integer> allHenergyBins = new HashMap<Point, Integer>();
+ private Map<Point, Integer> failHenergyBins = new HashMap<Point, Integer>();
+ private Map<Integer, Integer> allTimeBins = new HashMap<Integer, Integer>();
+ private Map<Integer, Integer> failTimeBins = new HashMap<Integer, Integer>();
+
+ public void addEvent(ClusterMatchEvent event, List<Cluster> reconClusters, List<SSPCluster> sspClusters) {
+ // Update the number of reconstructed and SSP clusters
+ // that have been seen so far.
+ int sspCount = sspClusters == null ? 0 : sspClusters.size();
+ int reconCount = reconClusters == null ? 0 : reconClusters.size();
+ this.sspClusters += sspCount;
+ this.reconClusters += reconCount;
+
+ // Update the pair state information.
+ matches += event.getMatches();
+ failEnergy += event.getEnergyFailures();
+ failHitCount += event.getHitCountFailures();
+ failPosition += event.getPositionFailures();
+
+ // In the special case that there are no SSP clusters, no pairs
+ // will be listed. All possible fails are known to have failed
+ // due to position.
+ if(sspClusters == null || sspClusters.isEmpty()) {
+ failPosition += (reconClusters == null ? 0 : reconClusters.size());
+ }
+
+ // Update the plotting information for reconstructed clusters.
+ for(Cluster cluster : reconClusters) {
+ // Update the hit count bin data.
+ Integer hitCountCount = reconHitCountBins.get(cluster.getCalorimeterHits().size());
+ if(hitCountCount == null) { reconHitCountBins.put(cluster.getCalorimeterHits().size(), 1); }
+ else { reconHitCountBins.put(cluster.getCalorimeterHits().size(), hitCountCount + 1); }
+
+ // Update the position bin data.
+ Point clusterPosition = TriggerDiagnosticUtil.getClusterPosition(cluster);
+ Integer positionCount = reconPositionBins.get(clusterPosition);
+ if(positionCount == null) { reconPositionBins.put(clusterPosition, 1); }
+ else { reconPositionBins.put(clusterPosition, positionCount + 1); }
+
+ // Update the energy bin data.
+ int energyBin = (int) Math.floor(cluster.getEnergy() / ENERGY_BIN);
+ Integer energyCount = reconEnergyBins.get(energyBin);
+ if(energyCount == null) { reconEnergyBins.put(energyBin, 1); }
+ else { reconEnergyBins.put(energyBin, energyCount + 1); }
+ }
+
+ // Update the plotting information for SSP clusters.
+ for(SSPCluster cluster : sspClusters) {
+ // Update the hit count bin data.
+ Integer hitCountCount = sspHitCountBins.get(cluster.getHitCount());
+ if(hitCountCount == null) { sspHitCountBins.put(cluster.getHitCount(), 1); }
+ else { sspHitCountBins.put(cluster.getHitCount(), hitCountCount + 1); }
+
+ // Update the position bin data.
+ Point clusterPosition = TriggerDiagnosticUtil.getClusterPosition(cluster);
+ Integer positionCount = sspPositionBins.get(clusterPosition);
+ if(positionCount == null) { sspPositionBins.put(clusterPosition, 1); }
+ else { sspPositionBins.put(clusterPosition, positionCount + 1); }
+
+ // Update the energy bin data.
+ int energyBin = (int) Math.floor(cluster.getEnergy() / ENERGY_BIN);
+ Integer energyCount = sspEnergyBins.get(energyBin);
+ if(energyCount == null) { sspEnergyBins.put(energyBin, 1); }
+ else { sspEnergyBins.put(energyBin, energyCount + 1); }
+ }
+
+ // Update the plotting information for SSP/reconstructed cluster
+ // pairs.
+ pairLoop:
+ for(ClusterMatchedPair pair : event.getMatchedPairs()) {
+ // If one of the pairs is null, then it is unmatched cluster
+ // and may be skipped.
+ if(pair.getReconstructedCluster() == null || pair.getSSPCluster() == null) {
+ continue pairLoop;
+ }
+
+ // Populate the bins for the "all" plots.
+ // Update the match time plots.
+ int timeBin = (int) Math.floor(TriggerDiagnosticUtil.getClusterTime(pair.getReconstructedCluster()) / TIME_BIN);
+ Integer timeCount = allTimeBins.get(timeBin);
+ if(timeCount == null) { allTimeBins.put(timeBin, 1); }
+ else { allTimeBins.put(timeBin, timeCount + 1); }
+
+ // Update the energy/hit difference plots.
+ int hitBin = getHitCountDifference(pair.getSSPCluster(), pair.getReconstructedCluster());
+ int energyBin = (int) Math.floor(getEnergyPercentDifference(pair.getSSPCluster(), pair.getReconstructedCluster()) / ENERGY_BIN);
+ Point henergyBin = new Point(hitBin, energyBin);
+ Integer henergyCount = allHenergyBins.get(henergyBin);
+ if(henergyCount == null) { allHenergyBins.put(henergyBin, 1); }
+ else { allHenergyBins.put(henergyBin, henergyCount + 1); }
+
+ // Populate the bins for the "fail" plots.
+ if(!pair.isMatch()) {
+ // Update the failed cluster position bins.
+ Point clusterPosition = TriggerDiagnosticUtil.getClusterPosition(pair.getReconstructedCluster());
+ Integer positionCount = failPositionBins.get(clusterPosition);
+ if(positionCount == null) { failPositionBins.put(clusterPosition, 1); }
+ else { failPositionBins.put(clusterPosition, positionCount + 1); }
+
+ // Update the failed match time plots.
+ timeCount = failTimeBins.get(timeBin);
+ if(timeCount == null) { failTimeBins.put(timeBin, 1); }
+ else { failTimeBins.put(timeBin, timeCount + 1); }
+
+ // Update the failed energy/hit difference plots.
+ henergyCount = failHenergyBins.get(henergyBin);
+ if(henergyCount == null) { failHenergyBins.put(henergyBin, 1); }
+ else { failHenergyBins.put(henergyBin, henergyCount + 1); }
+ }
+ }
+ }
+
+ /**
+ * Clears all statistical information and resets the object of its
+ * default, empty state.
+ */
+ @Override
+ public void clear() {
+ // Clear statistical data.
+ super.clear();
+
+ // Clear plot collections.
+ sspHitCountBins.clear();
+ reconHitCountBins.clear();
+ sspPositionBins.clear();
+ reconPositionBins.clear();
+ sspEnergyBins.clear();
+ reconEnergyBins.clear();
+ failPositionBins.clear();
+ allHenergyBins.clear();
+ failHenergyBins.clear();
+ allTimeBins.clear();
+ failTimeBins.clear();
+ }
+
+ /**
+ * Gets a copy of the statistical data stored in the object.
+ * @return Returns the data in a <code>ClusterStatModule</code>
+ * object.
+ */
+ public ClusterStatModule cloneStatModule() {
+ return new ClusterStatModule(this);
+ }
+
+ /**
+ * Solves the equation <code>|E_ssp / E_recon|</code>.
+ * @param sspCluster - The SSP cluster.
+ * @param reconCluster - The reconstructed cluster.
+ * @return Returns the solution to the equation as a <code>double
+ * </code> primitive.
+ */
+ private static final double getEnergyPercentDifference(SSPCluster sspCluster, Cluster reconCluster) {
+ return Math.abs((sspCluster.getEnergy() / reconCluster.getEnergy()));
+ }
+
+ /**
+ * Gets the difference in hit count between an SSP cluster and a
+ * reconstructed cluster.
+ * @param sspCluster - The SSP cluster.
+ * @param reconCluster - The reconstructed cluster.
+ * @return Returns the difference as an <code>int</code> primitive.
+ */
+ private static final int getHitCountDifference(SSPCluster sspCluster, Cluster reconCluster) {
+ return sspCluster.getHitCount() - TriggerDiagnosticUtil.getHitCount(reconCluster);
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,117 @@
+package org.hps.analysis.trigger.event;
+
+import org.hps.analysis.trigger.util.Pair;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.hps.readout.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 a
+ * 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 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/event/ClusterStatModule.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterStatModule.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterStatModule.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,109 @@
+package org.hps.analysis.trigger.event;
+
+/**
+ * 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;
+
+ /**
+ * Instantiates a <code>ClusterStatModule</code> with no statistics
+ * stored.
+ */
+ ClusterStatModule() { }
+
+ /**
+ * Instantiates a <code>ClusterStatModule</code> with no statistics
+ * cloned from the base object.
+ * @param base - The source for the statistical data.
+ */
+ ClusterStatModule(ClusterStatModule base) {
+ // Copy the statistical data into it.
+ sspClusters = base.sspClusters;
+ reconClusters = base.reconClusters;
+ matches = base.matches;
+ failEnergy = base.failEnergy;
+ failPosition = base.failPosition;
+ failHitCount = base.failHitCount;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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;
+ }
+}
Added: 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 (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,264 @@
+package org.hps.analysis.trigger.event;
+
+import java.util.List;
+
+import org.hps.analysis.trigger.util.ComponentUtils;
+import org.hps.analysis.trigger.util.Pair;
+import org.hps.analysis.trigger.util.PairTrigger;
+import org.hps.analysis.trigger.util.SinglesTrigger;
+import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.analysis.trigger.util.Trigger;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+
+public class TriggerEfficiencyModule {
+ // Store the statistics.
+ protected int[][] triggersSeenByType = new int[6][6];
+ protected int[][] triggersMatchedByType = new int[6][6];
+
+ /**
+ * Adds the number of matched triggers from the event to the total
+ * seen for each of the appropriate trigger types.
+ * @param eventTriggerType - The trigger type ID for the trigger that
+ * caused the event readout.
+ * @param event - A trigger statistical event.
+ */
+ public void addEvent(int eventTriggerType, TriggerMatchEvent event) {
+ // Iterate over the matched triggers and track how many were
+ // found of each trigger type.
+ List<Pair<Trigger<?>, SSPNumberedTrigger>> pairList = event.getMatchedReconPairs();
+ for(Pair<Trigger<?>, SSPNumberedTrigger> pair : pairList) {
+ // Update the appropriate counter based on the trigger type.
+ int triggerType = getTriggerType(pair.getFirstElement());
+ triggersMatchedByType[eventTriggerType][triggerType]++;
+ }
+ }
+
+ /**
+ * Adds singles triggers to the list of triggers seen.
+ * @param eventTriggerType - The trigger type ID for the event
+ * trigger type.
+ * @param singlesTriggers - A list of size two containing the
+ * triggers seen for each of the two singles triggers.
+ */
+ public void addSinglesTriggers(int eventTriggerType, List<List<? extends Trigger<?>>> singlesTriggers) {
+ // Note the trigger type.
+ int[] triggerType = { TriggerDiagnosticUtil.TRIGGER_SINGLES_1, TriggerDiagnosticUtil.TRIGGER_SINGLES_2 };
+
+ // Track the total number of singles triggers seen.
+ addTriggers(eventTriggerType, singlesTriggers, triggerType);
+ }
+
+ /**
+ * Adds pair triggers to the list of triggers seen.
+ * @param eventTriggerType - The trigger type ID for the event
+ * trigger type.
+ * @param pairTriggers - A list of size two containing the
+ * triggers seen for each of the two pair triggers.
+ */
+ public void addPairTriggers(int eventTriggerType, List<List<? extends Trigger<?>>> pairTriggers) {
+ // Note the trigger type.
+ int[] triggerType = { TriggerDiagnosticUtil.TRIGGER_PAIR_1, TriggerDiagnosticUtil.TRIGGER_PAIR_2 };
+
+ // Track the total number of singles triggers seen.
+ addTriggers(eventTriggerType, pairTriggers, triggerType);
+ }
+
+ /**
+ * Clears the data stored in the module.
+ */
+ public void clear() {
+ triggersSeenByType = new int[6][6];
+ triggersMatchedByType = new int[6][6];
+ }
+
+ @Override
+ public TriggerEfficiencyModule clone() {
+ // Create a new module.
+ TriggerEfficiencyModule clone = new TriggerEfficiencyModule();
+
+ // Clone the data.
+ clone.triggersMatchedByType = triggersMatchedByType.clone();
+ clone.triggersSeenByType = triggersSeenByType.clone();
+
+ // Return the clone.
+ return clone;
+ }
+
+ /**
+ * Gets the number of triggers matched in events that were caused
+ * by trigger <code>eventTriggerID</code> for <code>seenTriggerID
+ * </code> trigger.
+ * @param eventTriggerID - The trigger that caused the event.
+ * @param seenTriggerID - The trigger that was seen in the event.
+ * @return Returns the number of matches as an <code>int</code>.
+ */
+ public int getTriggersMatched(int eventTriggerID, int seenTriggerID) {
+ return triggersMatchedByType[eventTriggerID][seenTriggerID];
+ }
+
+ /**
+ * Gets the number of triggers seen in events that were caused
+ * by trigger <code>eventTriggerID</code> for <code>seenTriggerID
+ * </code> trigger.
+ * @param eventTriggerID - The trigger that caused the event.
+ * @param seenTriggerID - The trigger that was seen in the event.
+ * @return Returns the number of triggers as an <code>int</code>.
+ */
+ public int getTriggersSeen(int eventTriggerID, int seenTriggerID) {
+ return triggersSeenByType[eventTriggerID][seenTriggerID];
+ }
+
+ /**
+ * Prints the trigger statistics to the terminal as a table.
+ */
+ public void printModule() {
+ // 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;
+ for(String triggerName : TriggerDiagnosticUtil.TRIGGER_NAME) {
+ 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 < 6; seenTriggerID++) {
+ int valueSize = ComponentUtils.getDigits(triggersSeenByType[eventTriggerID][seenTriggerID]);
+ int cellSize = valueSize * 2 + 3;
+ 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);
+
+ // Calculate the total width of the table value header columns.
+ int headerTotalWidth = (TriggerDiagnosticUtil.TRIGGER_NAME.length * columnWidth)
+ + ((TriggerDiagnosticUtil.TRIGGER_NAME.length - 1) * columnSpacing);
+
+ // Write the table header.
+ String spacingText = ComponentUtils.getChars(' ', columnSpacing);
+ System.out.println(ComponentUtils.getChars(' ', columnWidth) + spacingText
+ + getCenteredString(seenName, headerTotalWidth));
+
+ // Create the format strings for the cell values.
+ String headerFormat = "%-" + columnWidth + "s" + spacingText;
+ String cellFormat = "%" + numWidth + "d / %" + numWidth + "d";
+ String nullText = getCenteredString(ComponentUtils.getChars('-', numWidth) + " / "
+ + ComponentUtils.getChars('-', numWidth), columnWidth) + spacingText;
+
+ // Print the column headers.
+ System.out.printf(headerFormat, sourceName);
+ for(String header : TriggerDiagnosticUtil.TRIGGER_NAME) {
+ 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 < 6; seenTriggerID++) {
+ if(seenTriggerID == eventTriggerID) { System.out.print(nullText); }
+ else {
+ String cellText = String.format(cellFormat, triggersMatchedByType[eventTriggerID][seenTriggerID],
+ triggersSeenByType[eventTriggerID][seenTriggerID]);
+ System.out.print(getCenteredString(cellText, columnWidth) + spacingText);
+ }
+ }
+
+ // Start a new line.
+ System.out.println();
+ }
+ }
+
+ /**
+ * Adds triggers in a generic way to the number of triggers seen.
+ * @param eventTriggerType - The trigger type ID for the event
+ * trigger type.
+ * @param triggerList - A list of size two containing the
+ * triggers seen for each of the two triggers of its type.
+ * @param triggerTypeID - The two trigger IDs corresponding to the
+ * list entries.
+ */
+ private void addTriggers(int eventTriggerType, List<List<? extends Trigger<?>>> triggerList, int[] triggerTypeID) {
+ // Track the total number of singles triggers seen.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ List<? extends Trigger<?>> triggers = triggerList.get(triggerNum);
+ triggersSeenByType[eventTriggerType][triggerTypeID[triggerNum]] += triggers.size();
+ }
+ }
+
+ /**
+ * 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());
+ }
+ }
+
+ /**
+ * Gets the trigger type identifier from a trigger object.
+ * @param trigger - A trigger.
+ * @return Returns the trigger type ID of the argument trigger.
+ */
+ private static final int getTriggerType(Trigger<?> trigger) {
+ // Choose the appropriate trigger type ID based on the class
+ // of the trigger.
+ if(trigger instanceof PairTrigger) {
+ // 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_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_1;
+ } else {
+ return TriggerDiagnosticUtil.TRIGGER_SINGLES_2;
+ }
+ }
+
+ // If the trigger type is not supported, throw an exception.
+ throw new IllegalArgumentException(String.format("Trigger type \"%s\" is not supported.",
+ trigger.getClass().getSimpleName()));
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,172 @@
+package org.hps.analysis.trigger.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hps.analysis.trigger.util.Pair;
+import org.hps.analysis.trigger.util.Trigger;
+import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+
+/**
+ * Tracks trigger pairs that were matched within an event. This can also
+ * track simulated SSP cluster pairs along with specifically which cuts
+ * passed and which did not.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerMatchEvent {
+ // Track trigger matching statistics.
+ private int[] sspInternalMatched = new int[2];
+ private int[] reconTriggersMatched = new int[2];
+ private int[][] triggerComp = new int[4][2];
+
+ // Track the matched trigger pairs.
+ private List<TriggerMatchedPair> sspPairList = new ArrayList<TriggerMatchedPair>();
+ private List<Pair<Trigger<?>, SSPNumberedTrigger>> reconPairList = new ArrayList<Pair<Trigger<?>, SSPNumberedTrigger>>();
+
+ /**
+ * Gets the number of times a cut of the given cut ID failed when
+ * SSP simulated triggers were compared to SSP bank triggers.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @param cutID - The ID of the cut.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getCutFailures(int triggerNumber, int cutID) {
+ // Validate the arguments.
+ if(triggerNumber !=0 && triggerNumber != 1) {
+ throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+ } if(cutID < 0 || cutID > 3) {
+ throw new IndexOutOfBoundsException(String.format("Cut ID \"%d\" is not valid.", cutID));
+ }
+
+ // Return the requested cut value.
+ return triggerComp[cutID][triggerNumber];
+ }
+
+ /**
+ * Gets the number of reconstructed cluster triggers that were
+ * matched successfully.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedReconTriggers() {
+ return reconPairList.size();
+ }
+
+ /**
+ * Gets the number of reconstructed cluster triggers that were
+ * matched successfully for a specific trigger.
+ * @param triggerNumber - The trigger number.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedReconTriggers(int triggerNumber) {
+ // Validate the arguments.
+ if(triggerNumber !=0 && triggerNumber != 1) {
+ throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+ }
+
+ // Return the trigger count.
+ return reconTriggersMatched[triggerNumber];
+ }
+
+ /**
+ * Gets the number of simulated SSP cluster triggers that were
+ * matched successfully.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedSSPTriggers() {
+ return sspPairList.size();
+ }
+
+ /**
+ * Gets the number of simulated SSP cluster triggers that were
+ * matched successfully for a specific trigger.
+ * @param triggerNumber - The trigger number.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedSSPTriggers(int triggerNumber) {
+ // Validate the arguments.
+ if(triggerNumber !=0 && triggerNumber != 1) {
+ throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+ }
+
+ // Return the trigger count.
+ return sspInternalMatched[triggerNumber];
+ }
+
+ /**
+ * Gets a list containing all reconstructed cluster triggers and
+ * their matched SSP bank triggers.
+ * @return Returns the trigger pairs as a <code>List</code>
+ * collection of <code>Pair</code> objects.
+ */
+ public List<Pair<Trigger<?>, SSPNumberedTrigger>> getMatchedReconPairs() {
+ return reconPairList;
+ }
+
+ /**
+ * Adds a reconstructed trigger and SSP bank trigger pair that is
+ * marked as matched for all trigger cuts.
+ * @param reconTrigger - The reconstructed cluster trigger.
+ * @param sspTrigger - The SSP bank trigger.
+ */
+ public void matchedReconPair(Trigger<?> reconTrigger, SSPNumberedTrigger sspTrigger) {
+ reconTriggersMatched[sspTrigger.isFirstTrigger() ? 0 : 1]++;
+ reconPairList.add(new Pair<Trigger<?>, SSPNumberedTrigger>(reconTrigger, sspTrigger));
+ }
+
+ /**
+ * Adds a simulated SSP trigger and SSP bank trigger pair that is
+ * marked as matched for all trigger cuts.
+ * @param simTrigger - The simulated SSP cluster trigger.
+ * @param sspTrigger - The SSP bank trigger.
+ */
+ public void matchedSSPPair(Trigger<?> simTrigger, SSPNumberedTrigger sspTrigger) {
+ // A null SSP trigger means that no match was found. This is
+ // treated as a failure due to time, which is not tracked.
+ if(sspTrigger != null) {
+ sspInternalMatched[sspTrigger.isFirstTrigger() ? 0 : 1]++;
+ sspPairList.add(new TriggerMatchedPair(simTrigger, sspTrigger, new boolean[] { true, true, true, true, true }));
+ }
+ }
+
+ /**
+ * Adds a simulated SSP trigger and SSP bank trigger pair along
+ * with the cuts that matched and did not.
+ * @param simTrigger - The simulated SSP cluster trigger.
+ * @param sspTrigger - The SSP bank trigger.
+ * @param cutsMatched - An array indicating which cuts matched and
+ * which did not.
+ */
+ public void matchedSSPPair(Trigger<?> simTrigger, SSPNumberedTrigger sspTrigger, boolean[] cutsMatched) {
+ // Store the full cut array.
+ boolean[] cutArray = cutsMatched;
+
+ // If the array is size 3, it is the a singles trigger. Update
+ // it to an array of size 4 for compatibility.
+ if(cutsMatched.length == 3) {
+ boolean[] tempArray = { true, true, true, true };
+ for(int cutIndex = 0; cutIndex < cutsMatched.length; cutIndex++) {
+ tempArray[cutIndex] = cutsMatched[cutIndex];
+ }
+ cutArray = tempArray;
+ }
+
+ // Add the trigger pair to the list.
+ TriggerMatchedPair triggerPair = new TriggerMatchedPair(simTrigger, sspTrigger, cutArray);
+ sspPairList.add(triggerPair);
+
+ // Track which cuts have failed.
+ boolean isMatched = true;
+ int triggerNum = triggerPair.isFirstTrigger() ? 0 : 1;
+ for(int cutIndex = 0; cutIndex < cutsMatched.length; cutIndex++) {
+ if(!cutsMatched[cutIndex]) {
+ triggerComp[cutIndex][triggerNum]++;
+ isMatched = false;
+ }
+ }
+
+ // If all the cuts are true, then the trigger pair is a match.
+ if(isMatched) { sspInternalMatched[triggerNum]++; }
+ }
+}
Added: 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 (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,65 @@
+package org.hps.analysis.trigger.event;
+
+import java.util.List;
+
+import org.hps.analysis.trigger.util.Trigger;
+import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+
+/**
+ * Tracks the trigger diagnostic statistics for trigger matching.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerMatchStatus extends TriggerStatModule {
+ /**
+ * Adds the statistical data stored in a trigger comparison event
+ * into this status tracking module.
+ * @param event - The event object.
+ * @param reconTriggers - A list of reconstructed cluster triggers.
+ * @param sspSimTriggers - A list of simulated SSP cluster triggers.
+ * @param sspBankTriggers - A list of SSP bank triggers.
+ */
+ public void addEvent(TriggerMatchEvent event, List<List<? extends Trigger<?>>> reconTriggers,
+ List<List<? extends Trigger<?>>> sspSimTriggers, List<? extends SSPNumberedTrigger> sspBankTriggers) {
+ // Check if there are more bank triggers than there are
+ // simulated SSP triggers.
+ int sspTriggerDiff = sspBankTriggers.size() - sspSimTriggers.size();
+ if(sspTriggerDiff > 0) {
+ reportedExtras += sspTriggerDiff;
+ }
+
+ // Increment the number of triggers of each type that have been
+ // seen so far.
+ sspTriggers += sspSimTriggers.get(0).size() + sspSimTriggers.get(1).size();
+ this.reconTriggers += reconTriggers.get(0).size() + reconTriggers.get(1).size();
+ reportedTriggers += sspBankTriggers.size();
+
+ // Increment the count for each cut failure type.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ for(int cutIndex = 0; cutIndex < 4; cutIndex++) {
+ triggerComp[cutIndex][triggerNum] += event.getCutFailures(triggerNum, cutIndex);
+ }
+ }
+
+ // Increment the total triggers found.
+ for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+ sspInternalMatched[triggerNum] += event.getMatchedSSPTriggers(triggerNum);
+ reconTriggersMatched[triggerNum] += event.getMatchedReconTriggers(triggerNum);
+ }
+ }
+
+ @Override
+ public void clear() {
+ // Clear the statistics module.
+ super.clear();
+ }
+
+ /**
+ * Gets a copy of the statistical data stored in the object.
+ * @return Returns the data in a <code>TriggerStatModule</code>
+ * object.
+ */
+ public TriggerStatModule cloneStatModule() {
+ return new TriggerStatModule(this);
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,140 @@
+package org.hps.analysis.trigger.event;
+
+import org.hps.analysis.trigger.util.Pair;
+import org.hps.analysis.trigger.util.PairTrigger;
+import org.hps.analysis.trigger.util.SinglesTrigger;
+import org.hps.analysis.trigger.util.Trigger;
+import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.readout.ecal.triggerbank.SSPPairTrigger;
+import org.hps.readout.ecal.triggerbank.SSPSinglesTrigger;
+
+/**
+ * Stores a pair of one simulated trigger and one SSP bank trigger that
+ * have been matched, along with which cuts are the same and which are
+ * different.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerMatchedPair extends Pair<Trigger<?>, SSPNumberedTrigger> {
+ // Cut IDs.
+ public static final int SINGLES_ENERGY_MIN = 0;
+ public static final int SINGLES_ENERGY_MAX = 1;
+ public static final int SINGLES_HIT_COUNT = 2;
+ public static final int PAIR_ENERGY_SUM = 0;
+ public static final int PAIR_ENERGY_DIFF = 1;
+ public static final int PAIR_ENERGY_SLOPE = 2;
+ public static final int PAIR_COPLANARITY = 3;
+
+ // Store the trigger result.
+ private boolean[] matchedCut = new boolean[4];
+
+ /**
+ * Creates a matched trigger pair of a simulated trigger and an SSP
+ * bank trigger.
+ * @param firstElement - The simulated trigger.
+ * @param secondElement - The SSP bank trigger.
+ * @param cutsMatched - An array indicating which cuts match and
+ * which do not.
+ */
+ public TriggerMatchedPair(Trigger<?> firstElement, SSPNumberedTrigger secondElement, boolean[] cutsMatched) {
+ // Store the trigger objects.
+ super(firstElement, secondElement);
+
+ // Set the matched cuts.
+ if(cutsMatched.length != 4) {
+ throw new IllegalArgumentException(String.format("The matched cuts array must be of size 4. Seen size = %d.", cutsMatched.length));
+ } else {
+ matchedCut[0] = cutsMatched[0];
+ matchedCut[1] = cutsMatched[1];
+ matchedCut[2] = cutsMatched[2];
+ matchedCut[3] = cutsMatched[3];
+ }
+ }
+
+ /**
+ * Gets whether the cut of the given cut ID passed the trigger.
+ * @param cutID - The cut ID.
+ * @return Returns <code>true</code> if the cut passed and
+ * <code>false</code> otherwise.
+ */
+ public boolean getCutResult(int cutID) {
+ if(cutID > matchedCut.length || cutID < 0) {
+ throw new IndexOutOfBoundsException(String.format("Cut ID \"%d\" is not valid.", cutID));
+ } else {
+ return matchedCut[cutID];
+ }
+ }
+
+ /**
+ * Gets the simulated trigger from the pair.
+ * @return Returns the simulated trigger as an object of the generic
+ * type <code>Trigger<?></code>.
+ */
+ public Trigger<?> getSimulatedTrigger() {
+ return getFirstElement();
+ }
+
+ /**
+ * Gets the type of cluster on which the trigger was simulated.
+ * @return Returns the type of cluster as a <code>Class<?></code>
+ * object.
+ */
+ public Class<?> getSimulatedTriggerType() {
+ return getFirstElement().getTriggerSource().getClass();
+ }
+
+ /**
+ * Gets the SSP bank trigger from the pair.
+ * @return Returns the SSP bank trigger as an object of the generic
+ * type <code>SSPNumberedTrigger</code>.
+ */
+ public SSPNumberedTrigger getSSPTrigger() {
+ return getSecondElement();
+ }
+
+ /**
+ * Returns whether the triggers in this pair are from the first
+ * trigger or not.
+ * @return Returns <code>true</code> if the triggers are from the
+ * first trigger and <code>false</code> otherwise.
+ */
+ public boolean isFirstTrigger() {
+ return getSecondElement().isFirstTrigger();
+ }
+
+ /**
+ * Indicates whether this is a pair of pair triggers.
+ * @return Returns <code>true</code> if the triggers are pair
+ * triggers and <code>false</code> otherwise.
+ */
+ public boolean isPairTrigger() {
+ if(getFirstElement() instanceof PairTrigger && getSecondElement() instanceof SSPPairTrigger) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether the triggers in this pair are from the second
+ * trigger or not.
+ * @return Returns <code>true</code> if the triggers are from the
+ * second trigger and <code>false</code> otherwise.
+ */
+ public boolean isSecondTrigger() {
+ return getSecondElement().isSecondTrigger();
+ }
+
+ /**
+ * Indicates whether this is a pair of singles triggers.
+ * @return Returns <code>true</code> if the triggers are singles
+ * triggers and <code>false</code> otherwise.
+ */
+ public boolean isSinglesTrigger() {
+ if(getFirstElement() instanceof SinglesTrigger && getSecondElement() instanceof SSPSinglesTrigger) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,166 @@
+package org.hps.analysis.trigger.event;
+
+/**
+ * Class <code>TriggerStatModule</code> stores the statistical data
+ * for trigger diagnostic trigger matching.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerStatModule {
+ // Track trigger verification statistical information.
+ protected int sspTriggers = 0;
+ protected int reconTriggers = 0;
+ protected int reportedTriggers = 0;
+ protected int reportedExtras = 0;
+ protected int[] sspInternalMatched = new int[2];
+ protected int[] reconTriggersMatched = new int[2];
+ protected int[][] triggerComp = new int[4][2];
+
+
+ /**
+ * Instantiates a <code>TriggerStatModule</code> with no statistics
+ * stored.
+ */
+ TriggerStatModule() { }
+
+ /**
+ * Instantiates a <code>TriggerStatModule</code> with no statistics
+ * cloned from the base object.
+ * @param base - The source for the statistical data.
+ */
+ protected TriggerStatModule(TriggerStatModule base) {
+ // Copy all of the values to the clone.
+ sspTriggers = base.sspTriggers;
+ reconTriggers = base.reconTriggers;
+ reportedTriggers = base.reportedTriggers;
+ reportedExtras = base.reportedExtras;
+ for(int i = 0; i < sspInternalMatched.length; i++) {
+ sspInternalMatched[i] = base.sspInternalMatched[i];
+ }
+ for(int i = 0; i < reconTriggersMatched.length; i++) {
+ reconTriggersMatched[i] = base.reconTriggersMatched[i];
+ }
+ for(int i = 0; i < triggerComp.length; i++) {
+ for(int j = 0; j < triggerComp[i].length; j++) {
+ triggerComp[i][j] = base.triggerComp[i][j];
+ }
+ }
+ }
+
+ /**
+ * Clears all the tracked values and resets them to the default
+ * empty value.
+ */
+ void clear() {
+ sspTriggers = 0;
+ reconTriggers = 0;
+ reportedTriggers = 0;
+ reportedExtras = 0;
+ sspInternalMatched = new int[2];
+ reconTriggersMatched = new int[2];
+ triggerComp = new int[4][2];
+ }
+
+ /**
+ * Gets the number of times a cut of the given cut ID failed when
+ * SSP simulated triggers were compared to SSP bank triggers.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @param cutID - The ID of the cut.
+ * @return Returns the number of times the cut failed as an
+ * <code>int</code> primitive.
+ */
+ public int getCutFailures(int triggerNumber, int cutID) {
+ // Validate the arguments.
+ if(triggerNumber !=0 && triggerNumber != 1) {
+ throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+ } if(cutID < 0 || cutID > 3) {
+ throw new IndexOutOfBoundsException(String.format("Cut ID \"%d\" is not valid.", cutID));
+ }
+
+ // Return the requested cut value.
+ return triggerComp[cutID][triggerNumber];
+ }
+
+ /**
+ * Gets the number of SSP bank triggers that were reported in excess
+ * of the number of simulated SSP triggers seen.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getExtraSSPBankTriggers() {
+ return reportedExtras;
+ }
+
+ /**
+ * Gets the number of reconstructed triggers that matched bank SSP
+ * triggers for both triggers.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedReconTriggers() {
+ return reconTriggersMatched[0] + reconTriggersMatched[1];
+ }
+
+ /**
+ * Gets the number of reconstructed triggers that matched bank SSP
+ * triggers.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedReconTriggers(int triggerNumber) {
+ // Validate the arguments.
+ if(triggerNumber !=0 && triggerNumber != 1) {
+ throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+ }
+
+ // Return the trigger count.
+ return reconTriggersMatched[triggerNumber];
+ }
+
+ /**
+ * Gets the number of simulated SSP triggers that matched bank SSP
+ * triggers for both triggers.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedSSPTriggers() {
+ return sspInternalMatched[0] + sspInternalMatched[1];
+ }
+
+ /**
+ * Gets the number of simulated SSP triggers that matched bank SSP
+ * triggers.
+ * @param triggerNumber - The trigger for which to get the value.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getMatchedSSPTriggers(int triggerNumber) {
+ // Validate the arguments.
+ if(triggerNumber !=0 && triggerNumber != 1) {
+ throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+ }
+
+ // Return the trigger count.
+ return sspInternalMatched[triggerNumber];
+ }
+
+ /**
+ * Gets the number of reconstructed cluster triggers seen.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getReconTriggerCount() {
+ return reconTriggers;
+ }
+
+ /**
+ * Gets the number of simulated SSP cluster triggers seen.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getSSPSimTriggerCount() {
+ return sspTriggers;
+ }
+
+ /**
+ * Gets the number of triggers reported by the SSP bank.
+ * @return Returns the value as an <code>int</code> primitive.
+ */
+ public int getSSPBankTriggerCount() {
+ return reportedTriggers;
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/ComponentUtils.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/ComponentUtils.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/ComponentUtils.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,126 @@
+package org.hps.analysis.trigger.util;
+
+import java.awt.Component;
+
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+
+/**
+ * Class <code>ComponentUtils</code> is a list of utility methods used
+ * by the trigger diagnostic GUI.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class ComponentUtils {
+ /** The default spacing used between a horizontal edge of one
+ * component and the horizontal edge of another. */
+ static final int hinternal = 10;
+ /** The default spacing used between a vertical edge of one
+ * component and the vertical edge of another. */
+ static final int vinternal = 10;
+ /** The default spacing used between a horizontal edge of one
+ * component and the edge of its parent component. */
+ static final int hexternal = 0;
+ /** The default spacing used between a vertical edge of one
+ * component and the edge of its parent component. */
+ static final int vexternal = 0;
+
+ /**
+ * Gets a <code>String</code> composed of a number of instances of
+ * character <code>c</code> equal to <code>number</code>.
+ * @param c - The character to repeat.
+ * @param number - The number of repetitions.
+ * @return Returns the repeated character as a <code>String</code>.
+ */
+ public static final String getChars(char c, int number) {
+ // Create a buffer to store the characters in.
+ StringBuffer s = new StringBuffer();
+
+ // Add the indicated number of instances.
+ for(int i = 0; i < number; i++) {
+ s.append(c);
+ }
+
+ // Return the string.
+ return s.toString();
+ }
+
+ /**
+ * Gets the number of digits in the base-10 String representation
+ * of an integer primitive. Negative signs are not included in the
+ * digit count.
+ * @param value - The value of which to obtain the length.
+ * @return Returns the number of digits in the String representation
+ * of the argument value.
+ */
+ public static final int getDigits(int value) {
+ return TriggerDiagnosticUtil.getDigits(value);
+ }
+
+ /**
+ * Gets the maximum value from a list of values.
+ * @param values - The values to compare.
+ * @return Returns the largest of the argument values.
+ * @throws IllegalArgumentException Occurs if no values are given.
+ */
+ public static final int max(int... values) throws IllegalArgumentException {
+ // Throw an error if no arguments are provided.
+ if(values == null || values.length == 0) {
+ throw new IllegalArgumentException("Can not determine maximum value from a list of 0 values.");
+ }
+
+ // If there is only one value, return it.
+ if(values.length == 1) { return values[0]; }
+
+ // Otherwise, get the largest value.
+ int largest = Integer.MIN_VALUE;
+ for(int value : values) {
+ if(value > largest) { largest = value; }
+ }
+
+ // Return the result.
+ return largest;
+ }
+
+ /**
+ * Gets the x-coordinate immediately to the right of the given
+ * component.
+ * @param c - The component of which to find the edge.
+ * @return Returns the x-coordinate as an <code>int</code> value.
+ */
+ static final int getNextX(Component c) {
+ return getNextX(c, 0);
+ }
+
+ /**
+ * Gets the x-coordinate a given distance to the right edge of the
+ * argument component.
+ * @param c - The component of which to find the edge.
+ * @param spacing - The additional spacing past the edge of the
+ * component to add.
+ * @return Returns the x-coordinate as an <code>int</code> value.
+ */
+ static final int getNextX(Component c, int spacing) {
+ return c.getX() + c.getWidth() + spacing;
+ }
+
+ /**
+ * Gets the y-coordinate immediately below the given component.
+ * @param c - The component of which to find the edge.
+ * @return Returns the y-coordinate as an <code>int</code> value.
+ */
+ static final int getNextY(Component c) {
+ return getNextY(c, 0);
+ }
+
+ /**
+ * Gets the y-coordinate a given distance below the bottom edge
+ * of the argument component.
+ * @param c - The component of which to find the edge.
+ * @param spacing - The additional spacing past the edge of the
+ * component to add.
+ * @return Returns the y-coordinate as an <code>int</code> value.
+ */
+ static final int getNextY(Component c, int spacing) {
+ return c.getY() + c.getHeight() + spacing;
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/OutputLogger.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/OutputLogger.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/OutputLogger.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,30 @@
+package org.hps.analysis.trigger.util;
+
+public class OutputLogger {
+ private static StringBuffer outputBuffer = new StringBuffer();
+
+ public static final void printf(String text, Object... args) {
+ outputBuffer.append(String.format(text, args));
+ }
+
+ public static final void println() { printf(String.format("%n")); }
+
+ public static final void println(String text) { printf(String.format("%s%n", text)); }
+
+ public static final void print(String text) { printf(text); }
+
+ public static final void printLog() {
+ System.out.println(outputBuffer.toString());
+ clearLog();
+ }
+
+ public static final void printNewLine() { println(); }
+
+ public static final void printNewLine(int quantity) {
+ for(int i = 0; i < quantity; i++) { println(); }
+ }
+
+ public static final void clearLog() {
+ outputBuffer = new StringBuffer();
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Pair.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Pair.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Pair.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,39 @@
+package org.hps.analysis.trigger.util;
+
+/**
+ * Class <code>Pair</code> represents a pair of two objects.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ * @param <E> - The object type of the first element in the pair.
+ * @param <F> - The object type of the second element in the pair.
+ */
+public class Pair<E, F> {
+ private final E firstObject;
+ private final F secondObject;
+
+ /**
+ * Creates a pair of the two indicated objects.
+ * @param firstObject - The first object.
+ * @param secondObject - The second object.
+ */
+ public Pair(E firstElement, F secondElement) {
+ this.firstObject = firstElement;
+ this.secondObject = secondElement;
+ }
+
+ /**
+ * Gets the first element of the pair.
+ * @return Returns the first element.
+ */
+ public E getFirstElement() {
+ return firstObject;
+ }
+
+ /**
+ * Gets the second element of the pair.
+ * @return Returns the second element.
+ */
+ public F getSecondElement() {
+ return secondObject;
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,166 @@
+package org.hps.analysis.trigger.util;
+
+import org.hps.readout.ecal.TriggerModule;
+
+public class PairTrigger<E> extends SinglesTrigger<E> {
+ // Define the supported trigger cuts.
+ private static final String PAIR_ENERGY_SUM_LOW = TriggerModule.PAIR_ENERGY_SUM_LOW;
+ private static final String PAIR_ENERGY_SUM_HIGH = TriggerModule.PAIR_ENERGY_SUM_HIGH;
+ private static final String PAIR_ENERGY_DIFFERENCE_HIGH = TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH;
+ private static final String PAIR_ENERGY_SLOPE_LOW = TriggerModule.PAIR_ENERGY_SLOPE_LOW;
+ private static final String PAIR_COPLANARITY_HIGH = TriggerModule.PAIR_COPLANARITY_HIGH;
+ private static final String PAIR_TIME_COINCIDENCE = "pairTimeCoincidence";
+
+ /**
+ * Instantiates a new <code>PairTrigger</code> with all cut
+ * states set to <code>false</code> and with the trigger source
+ * defined according to the specified object.
+ * @param source - The object from which the trigger cut states
+ * are derived.
+ */
+ public PairTrigger(E source, int triggerNum) {
+ // Instantiate the superclass.
+ super(source, triggerNum);
+
+ // Add the supported cuts types.
+ addValidCut(PAIR_ENERGY_SUM_LOW);
+ addValidCut(PAIR_ENERGY_SUM_HIGH);
+ addValidCut(PAIR_ENERGY_DIFFERENCE_HIGH);
+ addValidCut(PAIR_ENERGY_SLOPE_LOW);
+ addValidCut(PAIR_COPLANARITY_HIGH);
+ addValidCut(PAIR_TIME_COINCIDENCE);
+ }
+
+ /**
+ * Gets whether the pair energy sum lower bound cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateEnergySumLow() {
+ return getCutState(PAIR_ENERGY_SUM_LOW);
+ }
+
+ /**
+ * Gets whether the pair energy sum upper bound cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateEnergySumHigh() {
+ return getCutState(PAIR_ENERGY_SUM_HIGH);
+ }
+
+ /**
+ * Gets whether both the pair energy sum upper and lower bound cuts
+ * were met.
+ * @return Returns <code>true</code> if the cuts were met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateEnergySum() {
+ return getCutState(PAIR_ENERGY_SUM_HIGH);
+ }
+
+ /**
+ * Gets whether the pair energy difference cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateEnergyDifference() {
+ return getCutState(PAIR_ENERGY_SUM_HIGH);
+ }
+
+ /**
+ * Gets whether the pair energy slope cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateEnergySlope() {
+ return getCutState(PAIR_ENERGY_SLOPE_LOW);
+ }
+
+ /**
+ * Gets whether the pair coplanarity cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateCoplanarity() {
+ return getCutState(PAIR_COPLANARITY_HIGH);
+ }
+
+ /**
+ * Gets whether the time coincidence cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateTimeCoincidence() {
+ return getCutState(PAIR_TIME_COINCIDENCE);
+ }
+
+ /**
+ * Sets whether the conditions for the pair energy sum lower bound
+ * cut were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateEnergySumLow(boolean state) {
+ setCutState(PAIR_ENERGY_SUM_LOW, state);
+ }
+
+ /**
+ * Sets whether the conditions for the pair energy sum upper bound
+ * cut were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateEnergySumHigh(boolean state) {
+ setCutState(PAIR_ENERGY_SUM_HIGH, state);
+ }
+
+ /**
+ * Sets whether the conditions for the pair energy difference cut
+ * were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateEnergyDifference(boolean state) {
+ setCutState(PAIR_ENERGY_DIFFERENCE_HIGH, state);
+ }
+
+ /**
+ * Sets whether the conditions for the pair energy slope cut were
+ * met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateEnergySlope(boolean state) {
+ setCutState(PAIR_ENERGY_SLOPE_LOW, state);
+ }
+
+ /**
+ * Sets whether the conditions for the pair coplanarity cut were
+ * met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateCoplanarity(boolean state) {
+ setCutState(PAIR_COPLANARITY_HIGH, state);
+ }
+
+ /**
+ * Sets whether the conditions for the time coincidence cut were
+ * met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateTimeCoincidence(boolean state) {
+ setCutState(PAIR_TIME_COINCIDENCE, state);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("EClusterLow: %d; EClusterHigh %d; HitCount: %d; ESumLow: %d, ESumHigh: %d, EDiff: %d, ESlope: %d, Coplanarity: %d",
+ getStateClusterEnergyLow() ? 1 : 0, getStateClusterEnergyHigh() ? 1 : 0,
+ getStateHitCount() ? 1 : 0, getStateEnergySumLow() ? 1 : 0,
+ getStateEnergySumHigh() ? 1 : 0, getStateEnergyDifference() ? 1 : 0,
+ getStateEnergySlope() ? 1 : 0, getStateCoplanarity() ? 1 : 0);
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,153 @@
+package org.hps.analysis.trigger.util;
+
+import org.hps.readout.ecal.TriggerModule;
+
+public class SinglesTrigger<E> extends Trigger<E> {
+ // Define the supported trigger cuts.
+ private static final String CLUSTER_HIT_COUNT_LOW = TriggerModule.CLUSTER_HIT_COUNT_LOW;
+ private static final String CLUSTER_SEED_ENERGY_LOW = TriggerModule.CLUSTER_SEED_ENERGY_LOW;
+ private static final String CLUSTER_SEED_ENERGY_HIGH = TriggerModule.CLUSTER_SEED_ENERGY_HIGH;
+ private static final String CLUSTER_TOTAL_ENERGY_LOW = TriggerModule.CLUSTER_TOTAL_ENERGY_LOW;
+ private static final String CLUSTER_TOTAL_ENERGY_HIGH = TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH;
+
+ /**
+ * Instantiates a new <code>SinglesTrigger</code> with all cut
+ * states set to <code>false</code> and with the trigger source
+ * defined according to the specified object.
+ * @param source - The object from which the trigger cut states
+ * are derived.
+ */
+ public SinglesTrigger(E source, int triggerNum) {
+ // Instantiate the superclass.
+ super(source, triggerNum);
+
+ // Add the supported cuts types.
+ addValidCut(CLUSTER_HIT_COUNT_LOW);
+ addValidCut(CLUSTER_SEED_ENERGY_LOW);
+ addValidCut(CLUSTER_SEED_ENERGY_HIGH);
+ addValidCut(CLUSTER_TOTAL_ENERGY_LOW);
+ addValidCut(CLUSTER_TOTAL_ENERGY_HIGH);
+ }
+
+ /**
+ * Gets whether the cluster hit count cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateHitCount() {
+ return getCutState(CLUSTER_HIT_COUNT_LOW);
+ }
+
+ /**
+ * Gets whether the cluster seed energy lower bound cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateSeedEnergyLow() {
+ return getCutState(CLUSTER_SEED_ENERGY_LOW);
+ }
+
+ /**
+ * Gets whether the cluster seed energy upper bound cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateSeedEnergyHigh() {
+ return getCutState(CLUSTER_SEED_ENERGY_HIGH);
+ }
+
+ /**
+ * Gets whether both the cluster seed energy upper and lower bound
+ * cuts were met.
+ * @return Returns <code>true</code> if the cuts were met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateSeedEnergy() {
+ return getCutState(CLUSTER_SEED_ENERGY_LOW) && getCutState(CLUSTER_SEED_ENERGY_HIGH);
+ }
+
+ /**
+ * Gets whether the cluster total energy lower bound cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateClusterEnergyLow() {
+ return getCutState(CLUSTER_TOTAL_ENERGY_LOW);
+ }
+
+ /**
+ * Gets whether the cluster total energy upper bound cut was met.
+ * @return Returns <code>true</code> if the cut was met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateClusterEnergyHigh() {
+ return getCutState(CLUSTER_TOTAL_ENERGY_HIGH);
+ }
+
+ /**
+ * Gets whether both the cluster total energy upper and lower bound
+ * cuts were met.
+ * @return Returns <code>true</code> if the cuts were met and
+ * <code>false</code> otherwise.
+ */
+ public boolean getStateClusterEnergy() {
+ return getCutState(CLUSTER_TOTAL_ENERGY_LOW) && getCutState(CLUSTER_TOTAL_ENERGY_HIGH);
+ }
+
+ /**
+ * Sets whether the conditions for the cluster hit count cut were
+ * met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateHitCount(boolean state) {
+ setCutState(CLUSTER_HIT_COUNT_LOW, state);
+ }
+
+ /**
+ * Sets whether the conditions for the cluster seed energy lower
+ * bound cut were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateSeedEnergyLow(boolean state) {
+ setCutState(CLUSTER_SEED_ENERGY_LOW, state);
+ }
+
+ /**
+ * Sets whether the conditions for the cluster seed energy upper
+ * bound cut were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateSeedEnergyHigh(boolean state) {
+ setCutState(CLUSTER_SEED_ENERGY_HIGH, state);
+ }
+
+ /**
+ * Sets whether the conditions for the cluster total energy lower
+ * bound cut were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateClusterEnergyLow(boolean state) {
+ setCutState(CLUSTER_TOTAL_ENERGY_LOW, state);
+ }
+
+ /**
+ * Sets whether the conditions for the cluster total energy upper
+ * bound cut were met.
+ * @param state - <code>true</code> indicates that the cut conditions
+ * were met and <code>false</code> that they were not.
+ */
+ public void setStateClusterEnergyHigh(boolean state) {
+ setCutState(CLUSTER_TOTAL_ENERGY_HIGH, state);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("EClusterLow: %d; EClusterHigh %d; HitCount: %d",
+ getStateClusterEnergyLow() ? 1 : 0, getStateClusterEnergyHigh() ? 1 : 0,
+ getStateHitCount() ? 1 : 0);
+ }
+}
Added: java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Trigger.java
=============================================================================
--- java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Trigger.java (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/Trigger.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,152 @@
+package org.hps.analysis.trigger.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Class <code>Trigger</code> stores a set cut states indicating whether
+ * specific cut conditions associated with a trigger were met or not as
+ * well as the state of the overall trigger. It is the responsibility of
+ * implementing classes to specify the supported cut states and also
+ * to define when the trigger conditions are met.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public abstract class Trigger<E> {
+ // Track whether the trigger conditions were met.
+ private boolean passTrigger = false;
+ // Store the cut condition states.
+ private Map<String, Boolean> passMap = new HashMap<String, Boolean>();
+ // Store the cluster associated with the trigger.
+ private final E source;
+ // Store the trigger number.
+ private final int triggerNum;
+
+ /**
+ * Creates a new <code>Trigger</code> object with the argument
+ * specifying the object from whence the trigger state is derived.
+ * @param source - The trigger source object.
+ */
+ protected Trigger(E source) {
+ this(source, -1);
+ }
+
+ /**
+ * Creates a new <code>Trigger</code> object with the argument
+ * specifying the object from whence the trigger state is derived.
+ * @param source - The trigger source object.
+ * @param triggerNum - The number of the trigger.
+ */
+ protected Trigger(E source, int triggerNum) {
+ this.source = source;
+ this.triggerNum = triggerNum;
+ }
+
+ /**
+ * Adds a cut to the set of cuts tracked by this trigger.
+ * @param cut - The identifier for the cut.
+ */
+ protected void addValidCut(String cut) {
+ passMap.put(cut, new Boolean(false));
+ }
+
+ /**
+ * Gets the state of the specified cut.
+ * @param cut - The identifier for the cut.
+ * @return Returns <code>true</code> if the conditions for the
+ * specified cut were met and <code>false</code> otherwise.
+ * @throws IllegalArgumentException Occurs if the specified cut
+ * is not supported by the object.
+ */
+ protected boolean getCutState(String cut) throws IllegalArgumentException {
+ if(passMap.containsKey(cut)) {
+ return passMap.get(cut);
+ } else {
+ throw new IllegalArgumentException(String.format("Trigger cut \"%s\" is not a supported trigger cut.", cut));
+ }
+ }
+
+ /**
+ * Gets the number of the trigger. If the trigger has no number,
+ * it will return <code>-1</code>.
+ * @return Returns the trigger number as an <code>int</code>.
+ */
+ public int getTriggerNumber() {
+ return triggerNum;
+ }
+
+ /**
+ * Gets the object to which the trigger cuts are applied.
+ * @return Returns the trigger source object.
+ */
+ public E getTriggerSource() { return source; }
+
+ /**
+ * Gets whether the conditions for the trigger were met.
+ * @return Returns <code>true</code> if the conditions for the
+ * trigger were met and <code>false</code> if they were not.
+ */
+ public boolean getTriggerState() {
+ return passTrigger;
+ }
+
+ /**
+ * Removes a cut from the set of cuts tracked by the trigger.
+ * @param cut - The identifier for the cut.
+ */
+ protected void removeValidCut(String cut) {
+ passMap.remove(cut);
+ }
+
+ /**
+ * Checks whether the all of the trigger cut conditions were met.
+ * @return Returns <code>true</code> if all of the cut conditions
+ * were met and <code>false</code> otherwise.
+ */
+ private boolean isValidTrigger() {
+ // Iterate over all of the cuts and look for any that have not
+ // been met.
+ for(Entry<String, Boolean> cut : passMap.entrySet()) {
+ if(!cut.getValue()) { return false; }
+ }
+
+ // If there are no cut conditions that have not been met, then
+ // the trigger is valid.
+ return true;
+ }
+
+ /**
+ * Sets whether the conditions for the specified cut were met.
+ * @param cut - The identifier for the cut.
+ * @param state - <code>true</code> indicates that the conditions
+ * for the cut were met and <code>false</code> that they were not.
+ * @throws IllegalArgumentException Occurs if the specified cut
+ * is not supported by the object.
+ */
+ protected void setCutState(String cut, boolean state) throws IllegalArgumentException {
+ if(passMap.containsKey(cut)) {
+ // Set the cut state.
+ passMap.put(cut, state);
+
+ // If the cut state is true, then all cut conditions may have
+ // been met. Check whether this is true and, if so, set the
+ // trigger state accordingly.
+ if(state && isValidTrigger()) { passTrigger = true; }
+ else { passTrigger = false; }
+ } else {
+ throw new IllegalArgumentException(String.format("Trigger cut \"%s\" is not a supported trigger cut.", cut));
+ }
+ }
+
+ /**
+ * Indicates whether the specified cut state is tracked by this
+ * object or not.
+ * @param cut - The identifier for the cut.
+ * @return Returns <code>true</code> if the cut state is tracked
+ * by this object and <code>false</code> otherwise.
+ */
+ protected boolean supportsCut(String cut) {
+ return passMap.containsKey(cut);
+ }
+}
Added: 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 (added)
+++ java/trunk/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java Thu Mar 5 10:59:19 2015
@@ -0,0 +1,220 @@
+package org.hps.analysis.trigger.util;
+
+import java.awt.Point;
+
+import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
+
+/**
+ * Class <code>TriggerDiagnosticUtil</code> contains a series of
+ * utility methods that are used at various points throughout the
+ * trigger diagnostic package.
+ *
+ * @author Kyle McCarty <[log in to unmask]>
+ */
+public class TriggerDiagnosticUtil {
+ // Cluster match state variables.
+ public static final byte CLUSTER_STATE_MATCHED = 0;
+ public static final byte CLUSTER_STATE_FAIL_POSITION = 1;
+ public static final byte CLUSTER_STATE_FAIL_ENERGY = 2;
+ public static final byte CLUSTER_STATE_FAIL_HIT_COUNT = 3;
+ public static final byte CLUSTER_STATE_FAIL_UNKNOWN = 4;
+
+ // Trigger match cut IDs.
+ public static final int SINGLES_ENERGY_MIN = 0;
+ public static final int SINGLES_ENERGY_MAX = 1;
+ public static final int SINGLES_HIT_COUNT = 2;
+ public static final int PAIR_ENERGY_SUM = 0;
+ public static final int PAIR_ENERGY_DIFF = 1;
+ public static final int PAIR_ENERGY_SLOPE = 2;
+ 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" };
+
+ /**
+ * Convenience method that writes the position of a cluster in the
+ * form (ix, iy).
+ * @param cluster - The cluster.
+ * @return Returns the cluster position as a <code>String</code>.
+ */
+ public static final String clusterPositionString(Cluster cluster) {
+ return String.format("(%3d, %3d)",
+ cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"),
+ cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"));
+ }
+
+ /**
+ * Convenience method that writes the position of a cluster in the
+ * form (ix, iy).
+ * @param cluster - The cluster.
+ * @return Returns the cluster position as a <code>String</code>.
+ */
+ public static final String clusterPositionString(SSPCluster cluster) {
+ return String.format("(%3d, %3d)", cluster.getXIndex(), cluster.getYIndex());
+ }
+
+ /**
+ * Convenience method that writes the information in a cluster to
+ * a <code>String</code>.
+ * @param cluster - The cluster.
+ * @return Returns the cluster information as a <code>String</code>.
+ */
+ public static final String clusterToString(Cluster cluster) {
+ return String.format("Cluster at (%3d, %3d) with %.3f GeV and %d hits at %4.0f ns.",
+ cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"),
+ cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"),
+ cluster.getEnergy(), cluster.getCalorimeterHits().size(),
+ cluster.getCalorimeterHits().get(0).getTime());
+ }
+
+ /**
+ * Convenience method that writes the information in a cluster to
+ * a <code>String</code>.
+ * @param cluster - The cluster.
+ * @return Returns the cluster information as a <code>String</code>.
+ */
+ public static final String clusterToString(SSPCluster cluster) {
+ return String.format("Cluster at (%3d, %3d) with %.3f GeV and %d hits at %4d ns.",
+ cluster.getXIndex(), cluster.getYIndex(), cluster.getEnergy(),
+ cluster.getHitCount(), cluster.getTime());
+ }
+
+ /**
+ * Gets the x/y-indices of the cluster.
+ * @param cluster - The cluster of which to obtain the indices.
+ * @return Returns the indices as a <code>Point</code> object.
+ */
+ public static final Point getClusterPosition(Cluster cluster) {
+ return new Point(getXIndex(cluster), getYIndex(cluster));
+ }
+
+ /**
+ * Gets the x/y-indices of the cluster.
+ * @param cluster - The cluster of which to obtain the indices.
+ * @return Returns the indices as a <code>Point</code> object.
+ */
+ public static final Point getClusterPosition(SSPCluster cluster) {
+ return new Point(cluster.getXIndex(), cluster.getYIndex());
+ }
+
+ /**
+ * Gets the time stamp of the cluster in nanoseconds.
+ * @param cluster - The cluster.
+ * @return Returns the time-stamp.
+ */
+ public static final double getClusterTime(Cluster cluster) {
+ return cluster.getCalorimeterHits().get(0).getTime();
+ }
+
+ /**
+ * Gets the time stamp of the cluster in nanoseconds.
+ * @param cluster - The cluster.
+ * @return Returns the time-stamp.
+ */
+ public static final int getClusterTime(SSPCluster cluster) {
+ return cluster.getTime();
+ }
+
+ /**
+ * Gets the number of digits in the base-10 String representation
+ * of an integer primitive. Negative signs are not included in the
+ * digit count.
+ * @param value - The value of which to obtain the length.
+ * @return Returns the number of digits in the String representation
+ * of the argument value.
+ */
+ public static final int getDigits(int value) {
+ if(value < 0) { return Integer.toString(value).length() - 1; }
+ else { return Integer.toString(value).length(); }
+ }
+
+ /**
+ * Gets the number of hits in a cluster.
+ * @param cluster - The cluster.
+ * @return Returns the number of hits in the cluster.
+ */
+ public static final int getHitCount(Cluster cluster) {
+ return cluster.getCalorimeterHits().size();
+ }
+
+ /**
+ * Gets the number of hits in a cluster.
+ * @param cluster - The cluster.
+ * @return Returns the number of hits in the cluster.
+ */
+ public static final int getHitCount(SSPCluster cluster) {
+ return cluster.getHitCount();
+ }
+
+ /**
+ * Gets the x-index of the cluster's seed hit.
+ * @param cluster - The cluster.
+ * @return Returns the x-index.
+ */
+ public static final int getXIndex(Cluster cluster) {
+ return cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix");
+ }
+
+ /**
+ * Gets the x-index of the cluster's seed hit.
+ * @param cluster - The cluster.
+ * @return Returns the x-index.
+ */
+ public static final int getXIndex(SSPCluster cluster) {
+ return cluster.getXIndex();
+ }
+
+ /**
+ * Gets the y-index of the cluster's seed hit.
+ * @param cluster - The cluster.
+ * @return Returns the y-index.
+ */
+ public static final int getYIndex(Cluster cluster) {
+ return cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy");
+ }
+
+ /**
+ * Gets the y-index of the cluster's seed hit.
+ * @param cluster - The cluster.
+ * @return Returns the y-index.
+ */
+ public static final int getYIndex(SSPCluster cluster) {
+ return cluster.getYIndex();
+ }
+
+ /**
+ * Checks whether all of the hits in a cluster are within the safe
+ * region of the FADC output window.
+ * @param reconCluster - The cluster to check.
+ * @return Returns <code>true</code> if the cluster is safe and
+ * returns <code>false</code> otherwise.
+ */
+ public static final boolean isVerifiable(Cluster reconCluster, int nsa, int nsb, int windowWidth) {
+ // Iterate over the hits in the cluster.
+ for(CalorimeterHit hit : reconCluster.getCalorimeterHits()) {
+ // Check that none of the hits are within the disallowed
+ // region of the FADC readout window.
+ if(hit.getTime() <= nsb || hit.getTime() >= (windowWidth - nsa)) {
+ return false;
+ }
+
+ // Also check to make sure that the cluster does not have
+ // any negative energy hits. These are, obviously, wrong.
+ if(hit.getCorrectedEnergy() < 0.0) {
+ return false;
+ }
+ }
+
+ // If all of the cluster hits pass the time cut, the cluster
+ // is valid.
+ return true;
+ }
+}
|