Author: [log in to unmask] Date: Tue Mar 3 16:01:55 2015 New Revision: 2235 Log: Updated trigger diagnostics. Basic GUI component added. Still under construction. Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/ClusterMatchStatus.java java/trunk/users/src/main/java/org/hps/users/kmccarty/DiagSnapshot.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticGUIDriver.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/AbstractTablePanel.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ClusterTablePanel.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ComponentUtils.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/DiagnosticUpdatable.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/TableTextModel.java (with props) Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/PairTrigger.java java/trunk/users/src/main/java/org/hps/users/kmccarty/SinglesTrigger.java java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticDriver.java Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/ClusterMatchStatus.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/ClusterMatchStatus.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/ClusterMatchStatus.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,254 @@ +package org.hps.users.kmccarty; + +import java.awt.Point; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.hps.readout.ecal.triggerbank.SSPCluster; +import org.lcsim.event.Cluster; + +public class ClusterMatchStatus { + // Track cluster statistics. + private int sspClusters = 0; + private int reconClusters = 0; + private int matches = 0; + private int failEnergy = 0; + private int failPosition = 0; + private int failHitCount = 0; + + // 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. + 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; + } + + // 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 ot its + * default, empty state. + */ + public void clear() { + // Clear statistical data. + sspClusters = 0; + reconClusters = 0; + matches = 0; + failEnergy = 0; + failPosition = 0; + failHitCount = 0; + + // 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 the number of cluster pairs stored in this event that are + * marked with energy fail states. + * @return Returns the number of instances of this state as an + * <code>int</code> primitive. + */ + public int getEnergyFailures() { + return failEnergy; + } + + /** + * Gets the number of cluster pairs stored in this event that are + * marked with hit count fail states. + * @return Returns the number of instances of this state as an + * <code>int</code> primitive. + */ + public int getHitCountFailures() { + return failHitCount; + } + + /** + * Gets the number of cluster pairs stored in this event that are + * marked with position fail states. + * @return Returns the number of instances of this state as an + * <code>int</code> primitive. + */ + public int getMatches() { + return matches; + } + + /** + * Gets the number of cluster pairs stored in this event that are + * marked with position fail states. + * @return Returns the number of instances of this state as an + * <code>int</code> primitive. + */ + public int getPositionFailures() { + return failPosition; + } + + /** + * Gets the total number of verifiable reconstructed clusters seen. + * @return Returns the cluster count as an <code>int</code> + * primitive. + */ + public int getReconClusterCount() { + return reconClusters; + } + + /** + * Gets the total number of SSP bank clusters seen. + * @return Returns the cluster count as an <code>int</code> + * primitive. + */ + public int getSSPClusterCount() { + return sspClusters; + } + + /** + * Gets the 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); + } + + /** + * 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())); + } +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/DiagSnapshot.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/DiagSnapshot.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/DiagSnapshot.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,8 @@ +package org.hps.users.kmccarty; + +public class DiagSnapshot { + // UNDER CONSTRUCTION + // This is an empty file for now; it is still being built, but the + // table and driver won't work unless this object exists, so the + // empty class is included for the time being. +} Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/PairTrigger.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/PairTrigger.java (original) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/PairTrigger.java Tue Mar 3 16:01:55 2015 @@ -154,4 +154,13 @@ 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); + } } Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/SinglesTrigger.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/SinglesTrigger.java (original) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/SinglesTrigger.java Tue Mar 3 16:01:55 2015 @@ -143,4 +143,11 @@ 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); + } } Modified: java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticDriver.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticDriver.java (original) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticDriver.java Tue Mar 3 16:01:55 2015 @@ -17,6 +17,7 @@ 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; @@ -62,16 +63,8 @@ private boolean performPairTriggerVerification = true; // Efficiency tracking variables. - private static final int GLOBAL = 0; - private static final int LOCAL = 1; - private static final int EVENT = 2; - - private int[] clusterMatched = new int[3]; - private int[] clusterSSPCount = new int[3]; - private int[] clusterFailEnergy = new int[3]; - private int[] clusterReconCount = new int[3]; - private int[] clusterFailPosition = new int[3]; - private int[] clusterFailHitCount = new int[3]; + private ClusterMatchStatus clusterRunStats = new ClusterMatchStatus(); + private ClusterMatchStatus clusterLocalStats = new ClusterMatchStatus(); private int singlesSSPTriggers = 0; private int singlesReconMatched = 0; @@ -127,6 +120,16 @@ private boolean printPairTriggerInternalFail = true; private StringBuffer outputBuffer = new StringBuffer(); + // Cut index arrays for trigger verification. + private static final int ENERGY_MIN = 0; + private static final int ENERGY_MAX = 1; + private static final int HIT_COUNT = 2; + private static final int ENERGY_SUM = 0; + private static final int ENERGY_DIFF = 1; + private static final int ENERGY_SLOPE = 2; + private static final int COPLANARITY = 3; + private static final int TIME = 4; + /** * Define the trigger modules. This should be replaced by parsing * the DAQ configuration at some point. @@ -151,12 +154,12 @@ System.out.println("=== Cluster/Trigger Verification Settings ============================"); System.out.println("======================================================================"); - /* Runs 2040+ // Set the FADC settings. - nsa = 240; - nsb = 12; + 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); @@ -271,14 +274,15 @@ // Print the cluster verification data. System.out.println("Cluster Verification:"); - System.out.printf("\tRecon Clusters :: %d%n", clusterReconCount[GLOBAL]); - System.out.printf("\tSSP Clusters :: %d%n", clusterSSPCount[GLOBAL]); - System.out.printf("\tClusters Matched :: %d%n", clusterMatched[GLOBAL]); - System.out.printf("\tFailed (Position) :: %d%n", clusterFailPosition[GLOBAL]); - System.out.printf("\tFailed (Energy) :: %d%n", clusterFailEnergy[GLOBAL]); - System.out.printf("\tFailed (Hit Count) :: %d%n", clusterFailHitCount[GLOBAL]); - if(clusterReconCount[GLOBAL] == 0) { System.out.printf("\tCluster Efficiency :: N/A%n"); } - else { System.out.printf("\tCluster Efficiency :: %7.3f%%%n", 100.0 * clusterMatched[GLOBAL] / clusterReconCount[GLOBAL]); } + + 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 singles trigger verification data. int spaces = getPrintSpaces(singlesSSPTriggers, singlesReconTriggers, @@ -382,6 +386,16 @@ // ========================================================== // ==== Initialize the Event ================================ // ========================================================== + + // Print the verification header. + println(); + println(); + println("======================================================================"); + println("==== Cluster/Trigger Verification ===================================="); + println("======================================================================"); + + // Increment the total event count. + totalEvents++; // Reset the output buffer and print flags. outputBuffer = new StringBuffer(); @@ -426,19 +440,86 @@ } } */ + + + + // ========================================================== + // ==== 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()) { println("Trigger type :: Pulser"); } + else if(tiBank.isSingle0Trigger() || tiBank.isSingle1Trigger()) { println("Trigger type :: Singles"); } + else if(tiBank.isPair0Trigger() || tiBank.isPair1Trigger()) { println("Trigger type :: Pair"); } + else if(tiBank.isCalibTrigger()) { println("Trigger type :: Cosmic"); } + } + } + + // If there is an SSP bank, get the list of SSP clusters. + if(sspBank != null) { + sspClusters = sspBank.getClusters(); + if(sspClusters.size() == 1) { + println("1 SSP cluster found."); + } else { + printf("%d SSP clusters found.%n", sspClusters.size()); + } + } + } + + + + // ========================================================== + // ==== Establish Event Integrity =========================== + // ========================================================== + + // Check that all of the required objects are present. + if(sspBank == null) { + println("No SSP bank found for this event. No verification will be performed."); + if(verbose) { System.out.println(outputBuffer.toString()); } + return; + } if(tiBank == null) { + println("No TI bank found for this event. No verification will be performed."); + if(verbose) { System.out.println(outputBuffer.toString()); } + 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++; + println("Noise event detected. Skipping event..."); + if(verbose) { System.out.println(outputBuffer.toString()); } + return; + } + } // ========================================================== // ==== Obtain Reconstructed Clusters ======================= // ========================================================== - - // Print the verification header. - println(); - println(); - println("======================================================================"); - println("==== Cluster/Trigger Verification ===================================="); - println("======================================================================"); // Clear the list of triggers from previous events. for(int triggerNum = 0; triggerNum < 2; triggerNum++) { @@ -519,80 +600,6 @@ // ========================================================== - // ==== 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()) { println("Trigger type :: Pulser"); } - else if(tiBank.isSingle0Trigger() || tiBank.isSingle1Trigger()) { println("Trigger type :: Singles"); } - else if(tiBank.isPair0Trigger() || tiBank.isPair1Trigger()) { println("Trigger type :: Pair"); } - else if(tiBank.isCalibTrigger()) { println("Trigger type :: Cosmic"); } - } - } - - // If there is an SSP bank, get the list of SSP clusters. - if(sspBank != null) { - sspClusters = sspBank.getClusters(); - if(sspClusters.size() == 1) { - println("1 SSP cluster found."); - } else { - printf("%d SSP clusters found.%n", sspClusters.size()); - } - } - } - - - - // ========================================================== - // ==== Establish Event Integrity =========================== - // ========================================================== - - // Check that all of the required objects are present. - if(sspBank == null) { - println("No SSP bank found for this event. No verification will be performed."); - return; - } if(tiBank == null) { - println("No TI bank found for this event. No verification will be performed."); - return; - } - - - - // ========================================================== - // ==== Check the Noise Level =============================== - // ========================================================== - - // Increment the total event count. - totalEvents++; - - // 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++; - println("Noise event detected. Skipping event..."); - return; - } - } - - - - // ========================================================== // ==== Perform Event Verification ========================== // ========================================================== @@ -638,13 +645,8 @@ // Write a snapshot of the driver to the event stream. // TODO: Readout the snapshot!! - // Reset the local variables to zero. - clusterMatched[LOCAL] = 0; - clusterSSPCount[LOCAL] = 0; - clusterFailEnergy[LOCAL] = 0; - clusterReconCount[LOCAL] = 0; - clusterFailPosition[LOCAL] = 0; - clusterFailHitCount[LOCAL] = 0; + // Clear the local statistical data. + clusterLocalStats.clear(); } } @@ -721,8 +723,6 @@ // Track the number of cluster pairs that were matched and that // failed by failure type. - clusterSSPCount[EVENT] = 0; - clusterReconCount[EVENT] = 0; ClusterMatchEvent event = new ClusterMatchEvent(); @@ -751,9 +751,6 @@ // Add the cluster to the list. reconList.add(reconCluster); - - // Count the reconstructed clusters. - clusterReconCount[EVENT]++; } // Populate the SSP cluster map. @@ -770,9 +767,6 @@ // Add the cluster to the list. sspList.add(sspCluster); - - // Count the SSP clusters. - clusterSSPCount[EVENT]++; } @@ -797,18 +791,17 @@ // reason of position. The remainder of the loop may be // skipped, since there is nothing to check. if(sspList == null || sspList.isEmpty()) { - clusterFailPosition[EVENT] += reconList.size(); 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; - clusterFailPosition[EVENT] += (sspList.size() - reconList.size()); - } + if(sspList.size() < reconList.size()) { clusterFail = true; } // Get all possible permutations of SSP clusters. List<List<Pair>> permutations = getPermutations(reconList, sspList); @@ -835,9 +828,6 @@ // Try to match each pair. pairLoop: for(Pair pair : pairs) { - // Track the state of the current pair. - //int pairState = STATE_CLUSTER_UNDEFINED; - // Print the current reconstructed/SSP cluster pair. printf("\tP%d :: %s --> %s", permIndex, pair.reconCluster == null ? "None" : clusterToString(pair.reconCluster), @@ -861,16 +851,13 @@ if(pair.sspCluster.getHitCount() >= pair.reconCluster.getCalorimeterHits().size() - hitAcceptance && pair.sspCluster.getHitCount() <= pair.reconCluster.getCalorimeterHits().size() + hitAcceptance) { // Designate the pair as a match. - //pairState = STATE_CLUSTER_SUCCESS_MATCH; perm.pairMatch(pair.reconCluster, pair.sspCluster); printf(" [ %18s ]%n", "success: matched"); } else { - //pairState = STATE_CLUSTER_FAIL_HIT_COUNT; perm.pairFailHitCount(pair.reconCluster, pair.sspCluster); printf(" [ %18s ]%n", "failure: hit count"); } // End hit count check. } else { - //pairState = STATE_CLUSTER_FAIL_ENERGY; perm.pairFailEnergy(pair.reconCluster, pair.sspCluster); printf(" [ %18s ]%n", "failure: energy"); } // End energy check. @@ -900,20 +887,8 @@ } // End Crystal Position Loop // Add the event results to the global results. - clusterMatched[GLOBAL] += event.getMatches(); - clusterFailPosition[GLOBAL] += clusterFailPosition[EVENT]; - clusterFailEnergy[GLOBAL] += event.getEnergyFailures(); - clusterFailHitCount[GLOBAL] += event.getHitCountFailures(); - clusterReconCount[GLOBAL] += clusterReconCount[EVENT]; - clusterSSPCount[GLOBAL] += clusterSSPCount[EVENT]; - - // Add the event results to the local results. - clusterMatched[LOCAL] += event.getMatches(); - clusterFailPosition[LOCAL] += clusterFailPosition[EVENT]; - clusterFailEnergy[LOCAL] += event.getEnergyFailures(); - clusterFailHitCount[LOCAL] += event.getHitCountFailures(); - clusterReconCount[LOCAL] += clusterReconCount[EVENT]; - clusterSSPCount[LOCAL] += clusterSSPCount[EVENT]; + clusterRunStats.addEvent(event, reconClusters, sspClusters); + clusterLocalStats.addEvent(event, reconClusters, sspClusters); @@ -954,18 +929,24 @@ } else { 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. println(); println("Event Statistics:"); printf("\tRecon Clusters :: %d%n", reconClusters.size()); printf("\tClusters Matched :: %d%n", event.getMatches()); - printf("\tFailed (Position) :: %d%n", clusterFailPosition[EVENT]); + printf("\tFailed (Position) :: %d%n", failPosition); printf("\tFailed (Energy) :: %d%n", event.getEnergyFailures()); printf("\tFailed (Hit Count) :: %d%n", event.getHitCountFailures()); printf("\tCluster Efficiency :: %3.0f%%%n", 100.0 * event.getMatches() / reconClusters.size()); // Note whether there was a cluster match failure. - if(clusterMatched[EVENT] - reconClusters.size() != 0) { + if(event.getMatches() - reconClusters.size() != 0) { clusterFail = true; } } @@ -977,15 +958,66 @@ * simulated on reconstructed clusters to measure trigger efficiency. */ private void singlesTriggerVerification() { - // ========================================================== - // ==== Initialize Singles Trigger Verification ============= + // 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); + } + + private void triggerVerification(List<List<? extends Trigger<?>>> sspTriggerList, + List<List<? extends Trigger<?>>> reconTriggerList, boolean isSingles) { + + // ========================================================== + // ==== Initialize Trigger Verification ===================== // ========================================================== // Print the cluster verification header. println(); println(); println("======================================================================"); - println("=== Singles Trigger Verification ====================================="); + if(isSingles) { println("=== Singles Trigger Verification ====================================="); } + else { println("=== Pair Trigger Verification ========================================"); } println("======================================================================"); // Track the number of triggers seen and the number found. @@ -996,10 +1028,7 @@ // Track the number of times a given cut caused a trigger to // fail to match. - int[] eventEnergyMin = new int[2]; - int[] eventEnergyMax = new int[2]; - int[] eventHitCount = new int[2]; - int[] eventTime = new int[2]; + int[][] triggerComp = new int[5][2]; @@ -1008,52 +1037,45 @@ // ========================================================== // Get the list of triggers reported by the SSP. - List<SSPSinglesTrigger> sspTriggers = sspBank.getSinglesTriggers(); + List<? extends SSPNumberedTrigger> sspTriggers; + if(isSingles) { sspTriggers = sspBank.getSinglesTriggers(); } + else { sspTriggers = sspBank.getPairTriggers(); } // Output the SSP cluster singles triggers. println(); - println("SSP Cluster Singles Triggers"); + println("SSP Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers"); for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(SinglesTrigger<SSPCluster> simTrigger : sspSinglesTriggers.get(triggerNum)) { - printf("\tTrigger %d :: %s :: EClusterLow: %d; EClusterHigh %d; HitCount: %d%n", - (triggerNum + 1), clusterPositionString(simTrigger.getTriggerSource()), - simTrigger.getStateClusterEnergyLow() ? 1 : 0, - simTrigger.getStateClusterEnergyHigh() ? 1 : 0, - simTrigger.getStateHitCount() ? 1 : 0); - } - } - if(sspSinglesTriggers.get(0).size() + sspSinglesTriggers.get(1).size() == 0) { + for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) { + printf("\tTrigger %d :: %s :: %s%n", + (triggerNum + 1), triggerPositionString(simTrigger), + simTrigger.toString()); + } + } + if(sspTriggerList.get(0).size() + sspTriggerList.get(1).size() == 0) { println("\tNone"); } // Output the reconstructed cluster singles triggers. - println("Reconstructed Cluster Singles Triggers"); + println("Reconstructed Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers"); for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(SinglesTrigger<Cluster> simTrigger : reconSinglesTriggers.get(triggerNum)) { - printf("\tTrigger %d :: %s :: EClusterLow: %d; EClusterHigh %d; HitCount: %d%n", - (triggerNum + 1), clusterPositionString(simTrigger.getTriggerSource()), - simTrigger.getStateClusterEnergyLow() ? 1 : 0, - simTrigger.getStateClusterEnergyHigh() ? 1 : 0, - simTrigger.getStateHitCount() ? 1 : 0); - } - } - if(reconSinglesTriggers.get(0).size() + reconSinglesTriggers.get(1).size() == 0) { + for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) { + printf("\tTrigger %d :: %s :: %s%n", + (triggerNum + 1), triggerPositionString(simTrigger), + simTrigger.toString()); + } + } + if(reconTriggerList.get(0).size() + reconTriggerList.get(1).size() == 0) { println("\tNone"); } // Output the SSP reported triggers. - println("SSP Reported Singles Triggers"); - for(SSPSinglesTrigger sspTrigger : sspTriggers) { + println("SSP Reported " + (isSingles ? "Singles" : "Pair") + " Triggers"); + for(SSPTrigger sspTrigger : sspTriggers) { // Increment the number of SSP cluster singles triggers. sspReportedTriggers++; - // Get the trigger properties. - int triggerNum = sspTrigger.isFirstTrigger() ? 1 : 2; - // Print the trigger. - printf("\tTrigger %d :: %3d ns :: EClusterLow: %d; EClusterHigh %d; HitCount: %d%n", - triggerNum, sspTrigger.getTime(), sspTrigger.passCutEnergyMin() ? 1 : 0, - sspTrigger.passCutEnergyMax() ? 1 : 0, sspTrigger.passCutHitCount() ? 1 : 0); + printf("\t%s%n", sspTrigger.toString()); } if(sspReportedTriggers == 0) { println("\tNone"); } @@ -1066,21 +1088,22 @@ // Track which SSP triggers have been matched to avoid matching // multiple reconstructed SSP cluster triggers to the same SSP // trigger. - Set<SSPSinglesTrigger> sspTriggerSet = new HashSet<SSPSinglesTrigger>(); - Set<SinglesTrigger<SSPCluster>> simTriggerSet = new HashSet<SinglesTrigger<SSPCluster>>(); + 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 extraTriggers = sspTriggers.size() - (sspSinglesTriggers.get(0).size() + sspSinglesTriggers.get(1).size()); + int extraTriggers = sspTriggers.size() - (sspTriggerList.get(0).size() + sspTriggerList.get(1).size()); if(extraTriggers > 0) { sspReportedExtras += extraTriggers; - singlesInternalFail = true; + if(isSingles) { singlesInternalFail = true; } + else { pairInternalFail = true; } } // Iterate over the triggers. println(); println("SSP Reported Trigger --> SSP Cluster Trigger Match Status"); - for(SSPSinglesTrigger sspTrigger : sspTriggers) { + for(SSPNumberedTrigger sspTrigger : sspTriggers) { // Get the trigger information. int triggerNum = sspTrigger.isFirstTrigger() ? 0 : 1; boolean matchedTrigger = false; @@ -1088,14 +1111,14 @@ // Iterate over the SSP cluster simulated triggers and // look for a trigger that matches. matchLoop: - for(SinglesTrigger<SSPCluster> simTrigger : sspSinglesTriggers.get(triggerNum)) { + 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(compareSSPSinglesTriggers(sspTrigger, simTrigger)) { + if(compareTriggers(sspTrigger, simTrigger)) { matchedTrigger = true; sspTriggerSet.add(sspTrigger); simTriggerSet.add(simTrigger); @@ -1103,10 +1126,7 @@ break matchLoop; } - printf("\tTrigger %d :: %3d :: EClusterLow: %d; EClusterHigh %d; HitCount: %d :: Matched: %5b%n", - (triggerNum + 1), sspTrigger.getTime(), sspTrigger.passCutEnergyMin() ? 1 : 0, - sspTrigger.passCutEnergyMax() ? 1 : 0, sspTrigger.passCutHitCount() ? 1 : 0, - matchedTrigger); + printf("\t%s :: Matched: %5b%n", sspTrigger.toString(), matchedTrigger); } } @@ -1114,23 +1134,25 @@ // unmatched SSP reported trigger that most closely matches it. simLoop: for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(SinglesTrigger<SSPCluster> simTrigger : sspSinglesTriggers.get(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 foundBest = false; - boolean[] matchedCut = new boolean[3]; + boolean[] matchedCut = null; // Iterate over the reported triggers to find a match. reportedLoop: - for(SSPSinglesTrigger sspTrigger : sspTriggers) { + for(SSPNumberedTrigger sspTrigger : sspTriggers) { // If the two triggers have different times, this // trigger should be skipped. - if(sspTrigger.getTime() != simTrigger.getTriggerSource().getTime()) { + if(sspTrigger.getTime() != simTime) { continue reportedLoop; } @@ -1139,10 +1161,7 @@ if(sspTriggerSet.contains(sspTrigger)) { continue reportedLoop; } // Check each of the cuts. - boolean[] tempMatchedCut = new boolean[3]; - tempMatchedCut[0] = (simTrigger.getStateClusterEnergyLow() == sspTrigger.passCutEnergyMin()); - tempMatchedCut[1] = (simTrigger.getStateClusterEnergyHigh() == sspTrigger.passCutEnergyMax()); - tempMatchedCut[2] = (simTrigger.getStateHitCount() == sspTrigger.passCutHitCount()); + boolean[] tempMatchedCut = triggerCutMatch(simTrigger, sspTrigger); // Check each cut and see if this is a closer match // than the previous best match. @@ -1152,7 +1171,6 @@ // If the number of matched cuts exceeds the old // best result, this becomes the new best result. if(tempNumMatched > numMatched) { - foundBest = true; numMatched = tempNumMatched; matchedCut = tempMatchedCut; } @@ -1160,18 +1178,19 @@ // If some match was found, note what caused it to not // qualify as a complete match. - if(foundBest) { - if(!matchedCut[0]) { eventEnergyMin[triggerNum]++; } - if(!matchedCut[1]) { eventEnergyMax[triggerNum]++; } - if(!matchedCut[2]) { eventHitCount[triggerNum]++; } + if(matchedCut != null) { + for(int cutIndex = 0; cutIndex < matchedCut.length; cutIndex++) { + if(!matchedCut[cutIndex]) { triggerComp[cutIndex][triggerNum]++; } + } } // 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. else { - eventTime[triggerNum]++; - singlesInternalFail = true; + triggerComp[TIME][triggerNum]++; + if(isSingles) { singlesInternalFail = true; } + else { pairInternalFail = true; } } } } @@ -1179,7 +1198,7 @@ // ========================================================== - // ==== SSP Singles Trigger Efficiency ====================== + // ==== Trigger Efficiency ================================== // ========================================================== // Reset the SSP matched trigger set. @@ -1189,70 +1208,52 @@ println(); println("Recon Cluster Trigger --> SSP Reported Trigger Match Status"); for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(SinglesTrigger<Cluster> simTrigger : reconSinglesTriggers.get(triggerNum)) { - - printf("\tTrigger %d :: %s :: EClusterLow: %d; EClusterHigh %d; HitCount: %d%n", - (triggerNum + 1), clusterPositionString(simTrigger.getTriggerSource()), - simTrigger.getStateClusterEnergyLow() ? 1 : 0, - simTrigger.getStateClusterEnergyHigh() ? 1 : 0, - simTrigger.getStateHitCount() ? 1 : 0); - printf("\t\tCluster Energy :: %.3f GeV; Hit Count :: %d%n", simTrigger.getTriggerSource().getEnergy(), - simTrigger.getTriggerSource().getCalorimeterHits().size()); - printf("\t\tCluster Energy Cut :: [ %.3f GeV, %.3f GeV ]; Hit Count :: [ %.0f, INF )%n", - singlesTrigger[triggerNum].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW), - singlesTrigger[triggerNum].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH), - singlesTrigger[triggerNum].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW)); + for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) { + + 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(SSPTrigger sspTrigger : sspTriggers) { - // Only compare singles triggers. - if(sspTrigger instanceof SSPSinglesTrigger) { - // Cast the trigger. - SSPSinglesTrigger sspSingles = (SSPSinglesTrigger) sspTrigger; - - printf("\t\t\tTrigger %d :: %3d ns :: EClusterLow: %d; EClusterHigh %d; HitCount: %d", - sspSingles.isFirstTrigger() ? 1 : 2, - sspSingles.getTime(), - sspSingles.passCutEnergyMin() ? 1 : 0, - sspSingles.passCutEnergyMax() ? 1 : 0, - sspSingles.passCutHitCount() ? 1 : 0); - - // Only compare triggers if they are from the - // same trigger source. - if((triggerNum == 0 && sspSingles.isSecondTrigger()) - || (triggerNum == 1 && sspSingles.isFirstTrigger())) { - print(" [ fail; source ]%n"); + for(SSPNumberedTrigger sspTrigger : sspTriggers) { + 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())) { + print(" [ fail; source ]%n"); + continue matchLoop; + } + + // Only compare the singles trigger if it was + // not already matched to another trigger. + if(sspTriggerSet.contains(sspTrigger)) { + 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]) { + printf(" [ fail; %-9s ]%n", cutNames[typeIndex][cutIndex]); continue matchLoop; } - - // Only compare the singles trigger if it was - // not already matched to another trigger. - if(sspTriggerSet.contains(sspSingles)) { - print(" [ fail; matched ]%n"); - continue matchLoop; - } - - // Test each cut. - if(sspSingles.passCutEnergyMin() != simTrigger.getStateClusterEnergyLow()) { - print(" [ fail; E_min ]%n"); - continue matchLoop; - } if(sspSingles.passCutEnergyMax() != simTrigger.getStateClusterEnergyHigh()) { - print(" [ fail; E_max ]%n"); - continue matchLoop; - } if(sspSingles.passCutHitCount() != simTrigger.getStateHitCount()) { - print(" [ fail; hit count ]%n"); - continue matchLoop; - } - - // If all the trigger flags match, then the - // triggers are a match. - reconTriggersMatched++; - sspTriggerSet.add(sspSingles); - print(" [ success ]%n"); - break matchLoop; } + + // If all the trigger flags match, then the + // triggers are a match. + reconTriggersMatched++; + sspTriggerSet.add(sspTrigger); + print(" [ success ]%n"); + break matchLoop; } } } @@ -1265,8 +1266,9 @@ // Get the number of SSP and reconstructed cluster simulated // triggers. - int sspSimTriggers = sspSinglesTriggers.get(0).size() + sspSinglesTriggers.get(1).size(); - int reconSimTriggers = reconSinglesTriggers.get(0).size() + reconSinglesTriggers.get(1).size(); + 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. println(); @@ -1290,402 +1292,85 @@ } // Print the individual cut performances. - println(); - int halfSimTriggers = sspSimTriggers / 2; - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1)); - if(sspSimTriggers == 0) { - printf("\tCluster Energy Lower Bound :: %d / %d%n", eventEnergyMin[triggerNum], halfSimTriggers); - printf("\tCluster Energy Upper Bound :: %d / %d%n", eventEnergyMax[triggerNum], halfSimTriggers); - printf("\tCluster Hit Count :: %d / %d%n", eventHitCount[triggerNum], halfSimTriggers); - } else { - printf("\tCluster Energy Lower Bound :: %d / %d (%3.0f%%)%n", - eventEnergyMin[triggerNum], halfSimTriggers, (100.0 * eventEnergyMin[triggerNum] / halfSimTriggers)); - printf("\tCluster Energy Upper Bound :: %d / %d (%3.0f%%)%n", - eventEnergyMax[triggerNum], halfSimTriggers, (100.0 * eventEnergyMax[triggerNum] / halfSimTriggers)); - printf("\tCluster Hit Count :: %d / %d (%3.0f%%)%n", - eventHitCount[triggerNum], halfSimTriggers, (100.0 * eventHitCount[triggerNum] / halfSimTriggers)); - } - printf("\tExcess Reported Triggers :: %d%n", sspReportedExtras / 2); - } - - // Update the global trigger tracking variables. - singlesSSPTriggers += sspSimTriggers; - singlesReconMatched += reconTriggersMatched; - singlesReconTriggers += reconSimTriggers; - singlesInternalMatched += sspInternalMatched; - singlesReportedTriggers += sspReportedTriggers; - singlesReportedExtras += sspReportedExtras; - - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - globalEnergyMinCut[triggerNum] += eventEnergyMin[triggerNum]; - globalEnergyMaxCut[triggerNum] += eventEnergyMax[triggerNum]; - globalHitCountCut[triggerNum] += eventHitCount[triggerNum]; - globalSinglesTimeCut[triggerNum] += eventTime[triggerNum]; - } - - // Note whether the was a singles trigger match failure. + if(isSingles) { + println(); + for(int triggerNum = 0; triggerNum < 2; triggerNum++) { + printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1)); + if(sspSimTriggers == 0) { + printf("\tCluster Energy Lower Bound :: %d / %d%n", triggerComp[ENERGY_MIN][triggerNum], halfSimTriggers); + printf("\tCluster Energy Upper Bound :: %d / %d%n", triggerComp[ENERGY_MAX][triggerNum], halfSimTriggers); + printf("\tCluster Hit Count :: %d / %d%n", triggerComp[HIT_COUNT][triggerNum], halfSimTriggers); + } else { + printf("\tCluster Energy Lower Bound :: %d / %d (%3.0f%%)%n", + triggerComp[ENERGY_MIN][triggerNum], halfSimTriggers, (100.0 * triggerComp[ENERGY_MIN][triggerNum] / halfSimTriggers)); + printf("\tCluster Energy Upper Bound :: %d / %d (%3.0f%%)%n", + triggerComp[ENERGY_MAX][triggerNum], halfSimTriggers, (100.0 * triggerComp[ENERGY_MAX][triggerNum] / halfSimTriggers)); + printf("\tCluster Hit Count :: %d / %d (%3.0f%%)%n", + triggerComp[HIT_COUNT][triggerNum], halfSimTriggers, (100.0 * triggerComp[HIT_COUNT][triggerNum] / halfSimTriggers)); + } + printf("\tExcess Reported Triggers :: %d%n", sspReportedExtras / 2); + } + + // Update the global trigger tracking variables. + singlesSSPTriggers += sspSimTriggers; + singlesReconMatched += reconTriggersMatched; + singlesReconTriggers += reconSimTriggers; + singlesInternalMatched += sspInternalMatched; + singlesReportedTriggers += sspReportedTriggers; + singlesReportedExtras += sspReportedExtras; + + for(int triggerNum = 0; triggerNum < 2; triggerNum++) { + globalEnergyMinCut[triggerNum] += triggerComp[ENERGY_MIN][triggerNum]; + globalEnergyMaxCut[triggerNum] += triggerComp[ENERGY_MAX][triggerNum]; + globalHitCountCut[triggerNum] += triggerComp[HIT_COUNT][triggerNum]; + globalSinglesTimeCut[triggerNum] += triggerComp[TIME][triggerNum]; + } + } else { + for(int triggerNum = 0; triggerNum < 2; triggerNum++) { + println(); + printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1)); + if(sspSimTriggers == 0) { + printf("\tPair Energy Sum :: %d / %d%n", triggerComp[ENERGY_SUM][triggerNum], halfSimTriggers); + printf("\tPair Energy Difference :: %d / %d%n", triggerComp[ENERGY_DIFF][triggerNum], halfSimTriggers); + printf("\tPair Energy Slope :: %d / %d%n", triggerComp[ENERGY_SLOPE][triggerNum], halfSimTriggers); + printf("\tPair Coplanarity :: %d / %d%n", triggerComp[COPLANARITY][triggerNum], halfSimTriggers); + printf("\tPair Trigger Time :: %d / %d%n", triggerComp[TIME][triggerNum], halfSimTriggers); + } else { + printf("\tPair Energy Sum :: %d / %d (%3.0f%%)%n", + triggerComp[ENERGY_SUM][triggerNum], halfSimTriggers, (100.0 * triggerComp[ENERGY_SUM][triggerNum] / halfSimTriggers)); + printf("\tPair Energy Difference :: %d / %d (%3.0f%%)%n", + triggerComp[ENERGY_DIFF][triggerNum], halfSimTriggers, (100.0 * triggerComp[ENERGY_DIFF][triggerNum] / halfSimTriggers)); + printf("\tPair Energy Slope :: %d / %d (%3.0f%%)%n", + triggerComp[ENERGY_SLOPE][triggerNum], halfSimTriggers, (100.0 * triggerComp[ENERGY_SLOPE][triggerNum] / halfSimTriggers)); + printf("\tPair Coplanarity :: %d / %d (%3.0f%%)%n", + triggerComp[COPLANARITY][triggerNum], halfSimTriggers, (100.0 * triggerComp[COPLANARITY][triggerNum] / halfSimTriggers)); + printf("\tPair Trigger Time :: %d / %d (%3.0f%%)%n", + triggerComp[TIME][triggerNum], halfSimTriggers, (100.0 * triggerComp[TIME][triggerNum] / halfSimTriggers)); + } + printf("\tExcess Reported Triggers :: %d%n", sspReportedExtras / 2); + } + + // Update the global trigger tracking variables. + pairSSPTriggers += sspSimTriggers; + pairReconMatched += reconTriggersMatched; + pairReconTriggers += reconSimTriggers; + pairInternalMatched += sspInternalMatched; + pairReportedTriggers += sspReportedTriggers; + pairReportedExtras += sspReportedExtras; + + for(int triggerNum = 0; triggerNum < 2; triggerNum++) { + globalEnergySumCut[triggerNum] += triggerComp[ENERGY_SUM][triggerNum]; + globalEnergyDiffCut[triggerNum] += triggerComp[ENERGY_DIFF][triggerNum]; + globalEnergySlopeCut[triggerNum] += triggerComp[ENERGY_SLOPE][triggerNum]; + globalCoplanarityCut[triggerNum] += triggerComp[COPLANARITY][triggerNum]; + globalPairTimeCut[triggerNum] += triggerComp[TIME][triggerNum]; + } + } + + // Note whether the was a trigger match failure. if((reconTriggersMatched - reconSimTriggers != 0) || (sspInternalMatched - sspSimTriggers != 0)) { - singlesEfficiencyFail = 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() { - // ========================================================== - // ==== Initialize Pair Trigger Verification =============== - // ========================================================== - - // Print the cluster verification header. - println(); - println(); - println("======================================================================"); - println("=== Pair Trigger Verification ========================================"); - println("======================================================================"); - - // Track the number of triggers seen and the number found. - int sspReportedTriggers = 0; - int sspInternalMatched = 0; - int reconTriggersMatched = 0; - int sspReportedExtras = 0; - - int[] eventEnergySum = new int[2]; - int[] eventEnergyDiff = new int[2]; - int[] eventEnergySlope = new int[2]; - int[] eventCoplanarity = new int[2]; - int[] eventTime = new int[2]; - - - - // ========================================================== - // ==== Output Event Summary ================================ - // ========================================================== - - // Get the list of triggers reported by the SSP. - List<SSPPairTrigger> sspTriggers = sspBank.getPairTriggers(); - - // Output the SSP cluster pair triggers. - println(); - println("SSP Cluster Pair Triggers"); - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(PairTrigger<SSPCluster[]> simTrigger : sspPairsTriggers.get(triggerNum)) { - printf("\tTrigger %d :: %s, %s :: EClusterLow: %d; EClusterHigh %d; HitCount: %d; ESumLow: %d, ESumHigh: %d, EDiff: %d, ESlope: %d, Coplanarity: %d%n", - (triggerNum + 1), clusterPositionString(simTrigger.getTriggerSource()[0]), - clusterPositionString(simTrigger.getTriggerSource()[1]), - simTrigger.getStateClusterEnergyLow() ? 1 : 0, - simTrigger.getStateClusterEnergyHigh() ? 1 : 0, - simTrigger.getStateHitCount() ? 1 : 0, - simTrigger.getStateEnergySumLow() ? 1 : 0, - simTrigger.getStateEnergySumHigh() ? 1 : 0, - simTrigger.getStateEnergyDifference() ? 1 : 0, - simTrigger.getStateEnergySlope() ? 1 : 0, - simTrigger.getStateCoplanarity() ? 1 : 0); - } - } - if(sspPairsTriggers.get(0).size() + sspPairsTriggers.get(1).size() == 0) { - println("\tNone"); - } - - // Output the reconstructed cluster singles triggers. - println("Reconstructed Cluster Pair Triggers"); - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(PairTrigger<Cluster[]> simTrigger : reconPairsTriggers.get(triggerNum)) { - printf("\tTrigger %d :: %s, %s :: EClusterLow: %d; EClusterHigh %d; HitCount: %d; ESumLow: %d, ESumHigh: %d, EDiff: %d, ESlope: %d, Coplanarity: %d%n", - (triggerNum + 1), clusterPositionString(simTrigger.getTriggerSource()[0]), - clusterPositionString(simTrigger.getTriggerSource()[1]), - simTrigger.getStateClusterEnergyLow() ? 1 : 0, - simTrigger.getStateClusterEnergyHigh() ? 1 : 0, - simTrigger.getStateHitCount() ? 1 : 0, - simTrigger.getStateEnergySumLow() ? 1 : 0, - simTrigger.getStateEnergySumHigh() ? 1 : 0, - simTrigger.getStateEnergyDifference() ? 1 : 0, - simTrigger.getStateEnergySlope() ? 1 : 0, - simTrigger.getStateCoplanarity() ? 1 : 0); - } - } - if(reconPairsTriggers.get(0).size() + reconPairsTriggers.get(1).size() == 0) { - println("\tNone"); - } - - // Output the SSP reported triggers. - println("SSP Reported Pair Triggers"); - for(SSPPairTrigger sspTrigger : sspTriggers) { - // Increment the number of SSP cluster singles triggers. - sspReportedTriggers++; - - // Get the trigger properties. - int triggerNum = sspTrigger.isFirstTrigger() ? 1 : 2; - - // Print the trigger. - printf("\tTrigger %d :: %3d ns :: ESum: %d, EDiff: %d, ESlope: %d, Coplanarity: %d%n", - triggerNum, sspTrigger.getTime(), - sspTrigger.passCutEnergySum() ? 1 : 0, sspTrigger.passCutEnergyDifference() ? 1 : 0, - sspTrigger.passCutEnergySlope() ? 1 : 0, sspTrigger.passCutCoplanarity() ? 1 : 0); - } - if(sspReportedTriggers == 0) { 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<SSPPairTrigger> sspTriggerSet = new HashSet<SSPPairTrigger>(); - Set<PairTrigger<SSPCluster[]>> simTriggerSet = new HashSet<PairTrigger<SSPCluster[]>>(); - - // Track the number of SSP reported triggers that are found in - // excess of the SSP simulated triggers. - int extraTriggers = sspTriggers.size() - (sspPairsTriggers.get(0).size() + sspPairsTriggers.get(1).size()); - if(extraTriggers > 0) { - sspReportedExtras += extraTriggers; - pairInternalFail = true; - } - - // Iterate over the triggers. - println(); - println("SSP Reported Trigger --> SSP Cluster Trigger Match Status"); - for(SSPPairTrigger 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(PairTrigger<SSPCluster[]> simTrigger : sspPairsTriggers.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(compareSSPPairTriggers(sspTrigger, simTrigger)) { - matchedTrigger = true; - sspTriggerSet.add(sspTrigger); - simTriggerSet.add(simTrigger); - sspInternalMatched++; - break matchLoop; - } - - printf("\tTrigger %d :: %3d ns :: ESum: %d, EDiff: %d, ESlope: %d, Coplanarity: %d :: Matched: %5b%n", - triggerNum, sspTrigger.getTime(), sspTrigger.passCutEnergySum() ? 1 : 0, - sspTrigger.passCutEnergyDifference() ? 1 : 0, sspTrigger.passCutEnergySlope() ? 1 : 0, - sspTrigger.passCutCoplanarity() ? 1 : 0, 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(PairTrigger<SSPCluster[]> simTrigger : sspPairsTriggers.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. - int simTime = 0; - if(simTrigger.getTriggerSource()[0].getYIndex() < 0) { - simTime = simTrigger.getTriggerSource()[0].getTime(); - } else { simTime = simTrigger.getTriggerSource()[1].getTime(); } - - // Track the match statistics for each reported trigger - // so that the closest match may be found. - int numMatched = -1; - boolean foundBest = false; - boolean[] matchedCut = new boolean[4]; - - // Iterate over the reported triggers to find a match. - reportedLoop: - for(SSPPairTrigger 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 = new boolean[4]; - tempMatchedCut[0] = (simTrigger.getStateEnergySum() == sspTrigger.passCutEnergySum()); - tempMatchedCut[1] = (simTrigger.getStateEnergyDifference() == sspTrigger.passCutEnergyDifference()); - tempMatchedCut[2] = (simTrigger.getStateEnergySlope() == sspTrigger.passCutEnergySlope()); - tempMatchedCut[3] = (simTrigger.getStateCoplanarity() == sspTrigger.passCutCoplanarity()); - - // 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) { - foundBest = true; - numMatched = tempNumMatched; - matchedCut = tempMatchedCut; - } - } - - // If some match was found, note what caused it to not - // qualify as a complete match. - if(foundBest) { - if(!matchedCut[0]) { eventEnergySum[triggerNum]++; } - if(!matchedCut[1]) { eventEnergyDiff[triggerNum]++; } - if(!matchedCut[2]) { eventEnergySlope[triggerNum]++; } - if(!matchedCut[3]) { eventCoplanarity[triggerNum]++; } - } - - // 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. - else { - eventTime[triggerNum]++; - pairInternalFail = true; - } - } - } - - - - // ========================================================== - // ==== SSP Pair Trigger Efficiency ========================= - // ========================================================== - - // Reset the SSP matched trigger set. - sspTriggerSet.clear(); - - // Iterate over the reconstructed cluster pair triggers. - println(); - println("Recon Cluster Trigger --> SSP Reported Trigger Match Status"); - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - for(PairTrigger<Cluster[]> simTrigger : reconPairsTriggers.get(triggerNum)) { - // Track whether the trigger was matched. - boolean matchedTrigger = false; - - // Iterate over the SSP reported triggers and compare - // them to the reconstructed cluster simulated trigger. - matchLoop: - for(SSPTrigger sspTrigger : sspTriggers) { - // Only compare pair triggers. - if(sspTrigger instanceof SSPPairTrigger) { - // Cast the trigger. - SSPPairTrigger sspPair = (SSPPairTrigger) sspTrigger; - - // Only compare the pair trigger if it was - // not already matched to another trigger. - if(sspTriggerSet.contains(sspPair)) { continue matchLoop; } - - // Compare the triggers. - if(compareReconPairTriggers(sspPair, simTrigger)) { - reconTriggersMatched++; - matchedTrigger = true; - sspTriggerSet.add(sspPair); - break matchLoop; - } - } - } - - // Print the trigger matching status. - printf("\tTrigger %d :: %s, %s :: EClusterLow: %d; EClusterHigh %d; HitCount: %d; ESumLow: %d, ESumHigh: %d, EDiff: %d, ESlope: %d, Coplanarity: %d :: Matched: %5b%n", - (triggerNum + 1), clusterPositionString(simTrigger.getTriggerSource()[0]), - clusterPositionString(simTrigger.getTriggerSource()[1]), - simTrigger.getStateClusterEnergyLow() ? 1 : 0, - simTrigger.getStateClusterEnergyHigh() ? 1 : 0, - simTrigger.getStateHitCount() ? 1 : 0, - simTrigger.getStateEnergySumLow() ? 1 : 0, - simTrigger.getStateEnergySumHigh() ? 1 : 0, - simTrigger.getStateEnergyDifference() ? 1 : 0, - simTrigger.getStateEnergySlope() ? 1 : 0, - simTrigger.getStateCoplanarity() ? 1 : 0, matchedTrigger); - } - } - - - - // ========================================================== - // ==== Output Event Results ================================ - // ========================================================== - - // Get the number of SSP and reconstructed cluster simulated - // triggers. - int sspSimTriggers = sspPairsTriggers.get(0).size() + sspPairsTriggers.get(1).size(); - int reconSimTriggers = reconPairsTriggers.get(0).size() + reconPairsTriggers.get(1).size(); - int halfSimTriggers = sspSimTriggers / 2; - - // Print event statistics. - println(); - println("Event Statistics:"); - printf("\tSSP Cluster Sim Triggers :: %d%n", sspSimTriggers); - printf("\tRecon Cluster Sim Triggers :: %d%n", reconSimTriggers); - printf("\tSSP Reported Triggers :: %d%n", sspReportedTriggers); - if(sspSimTriggers == 0) { - printf("\tInternal Efficiency :: %d / %d (N/A)%n", - sspInternalMatched, sspSimTriggers); - } else { - printf("\tInternal Efficiency :: %d / %d (%3.0f%%)%n", - sspInternalMatched, sspSimTriggers, (100.0 * sspInternalMatched / sspSimTriggers)); - } - if(reconSimTriggers == 0) { - printf("\tTrigger Efficiency :: %d / %d (N/A)%n", - reconTriggersMatched, reconSimTriggers); - } else { - printf("\tTrigger Efficiency :: %d / %d (%3.0f%%)%n", - reconTriggersMatched, reconSimTriggers, (100.0 * reconTriggersMatched / reconSimTriggers)); - } - - // Print the individual cut performances. - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - println(); - printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1)); - if(sspSimTriggers == 0) { - printf("\tPair Energy Sum :: %d / %d%n", eventEnergySum[triggerNum], halfSimTriggers); - printf("\tPair Energy Difference :: %d / %d%n", eventEnergyDiff[triggerNum], halfSimTriggers); - printf("\tPair Energy Slope :: %d / %d%n", eventEnergySlope[triggerNum], halfSimTriggers); - printf("\tPair Coplanarity :: %d / %d%n", eventCoplanarity[triggerNum], halfSimTriggers); - printf("\tPair Trigger Time :: %d / %d%n", eventTime[triggerNum], halfSimTriggers); - } else { - printf("\tPair Energy Sum :: %d / %d (%3.0f%%)%n", - eventEnergySum[triggerNum], halfSimTriggers, (100.0 * eventEnergySum[triggerNum] / halfSimTriggers)); - printf("\tPair Energy Difference :: %d / %d (%3.0f%%)%n", - eventEnergyDiff[triggerNum], halfSimTriggers, (100.0 * eventEnergyDiff[triggerNum] / halfSimTriggers)); - printf("\tPair Energy Slope :: %d / %d (%3.0f%%)%n", - eventEnergySlope[triggerNum], halfSimTriggers, (100.0 * eventEnergySlope[triggerNum] / halfSimTriggers)); - printf("\tPair Coplanarity :: %d / %d (%3.0f%%)%n", - eventCoplanarity[triggerNum], halfSimTriggers, (100.0 * eventCoplanarity[triggerNum] / halfSimTriggers)); - printf("\tPair Trigger Time :: %d / %d (%3.0f%%)%n", - eventTime[triggerNum], halfSimTriggers, (100.0 * eventTime[triggerNum] / halfSimTriggers)); - } - printf("\tExcess Reported Triggers :: %d%n", sspReportedExtras / 2); - } - - // Update the global trigger tracking variables. - pairSSPTriggers += sspSimTriggers; - pairReconMatched += reconTriggersMatched; - pairReconTriggers += reconSimTriggers; - pairInternalMatched += sspInternalMatched; - pairReportedTriggers += sspReportedTriggers; - pairReportedExtras += sspReportedExtras; - - for(int triggerNum = 0; triggerNum < 2; triggerNum++) { - globalEnergySumCut[triggerNum] += eventEnergySum[triggerNum]; - globalEnergyDiffCut[triggerNum] += eventEnergyDiff[triggerNum]; - globalEnergySlopeCut[triggerNum] += eventEnergySlope[triggerNum]; - globalCoplanarityCut[triggerNum] += eventCoplanarity[triggerNum]; - globalPairTimeCut[triggerNum] += eventTime[triggerNum]; - } - - // Note whether the was a singles trigger match failure. - if((reconTriggersMatched - reconSimTriggers != 0) || (sspInternalMatched - sspSimTriggers != 0)) { - pairEfficiencyFail = true; + if(isSingles) { singlesEfficiencyFail = true; } + else { pairEfficiencyFail = true; } } } @@ -2031,6 +1716,41 @@ } /** + * 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. @@ -2088,40 +1808,6 @@ // 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; - } - - /** - * Compares a trigger from the SSP bank to a trigger simulated on - * an reconstructed 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 compareReconPairTriggers(SSPPairTrigger bankTrigger, PairTrigger<Cluster[]> simTrigger) { - // Check that the trigger flags are all the same. Start with - // energy sum. if(bankTrigger.passCutEnergySum() != simTrigger.getStateEnergySum()) { return false; } @@ -2301,6 +1987,138 @@ } /** + * 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 clusterPositionString((SSPCluster) source); + } else if(source instanceof Cluster) { + return clusterPositionString((Cluster) source); + } else if(source instanceof SSPCluster[]) { + SSPCluster[] sourcePair = (SSPCluster[]) source; + if(sourcePair.length == 2) { + return String.format("%s, %s", clusterPositionString(sourcePair[0]), + clusterPositionString(sourcePair[1])); + } + } else if(source instanceof Cluster[]) { + Cluster[] sourcePair = (Cluster[]) source; + if(sourcePair.length == 2) { + return String.format("%s, %s", clusterPositionString(sourcePair[0]), + 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())); + } + + 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())); + } + + /** * Class <code>Pair</code> provides a convenient means of putting * a reconstructed cluster and an SSP cluster in the same object * for cluster matching. Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticGUIDriver.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticGUIDriver.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerDiagnosticGUIDriver.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,43 @@ +package org.hps.users.kmccarty; + +import java.util.List; + +import javax.swing.JFrame; + +import org.hps.users.kmccarty.diagpanel.ClusterTablePanel; +import org.lcsim.event.EventHeader; +import org.lcsim.util.Driver; + +public class TriggerDiagnosticGUIDriver extends Driver { + private JFrame window = new JFrame(); + private ClusterTablePanel clusterTable = new ClusterTablePanel(); + private String diagnosticCollectionName = "DiagnosticSnapshot"; + + @Override + public void startOfData() { + window.add(clusterTable); + window.setVisible(true); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.setSize(500, 400); + } + + @Override + public void process(EventHeader event) { + // Updates are only performed if a diagnostic snapshot object + // exists. Otherwise, do nothing. + if(event.hasCollection(DiagSnapshot.class, diagnosticCollectionName)) { + // Get the snapshot collection. + List<DiagSnapshot> snapshotList = event.get(DiagSnapshot.class, diagnosticCollectionName); + + // Get the snapshot. There will only ever be one. + DiagSnapshot snapshot = snapshotList.get(0); + + // Feed it to the table. + clusterTable.updatePanel(snapshot); + } + } + + public void setDiagnosticCollectionName(String name) { + diagnosticCollectionName = name; + } +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/AbstractTablePanel.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/AbstractTablePanel.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/AbstractTablePanel.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,230 @@ +package org.hps.users.kmccarty.diagpanel; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; + +/** + * Class <code>AbstractTablePanel</code> displays two <code>JTable</code> + * objects side-by-side with headers above them. The left table displays + * statistical data for recent events processed with trigger diagnostics + * while the right table displays the same, but over the course of the + * entire run.<br/> + * <br/> + * This implements the interface <code>DiagnosticUpdatable</code>. + * + * @author Kyle McCarty <[log in to unmask]> + * @see JPanel + * @see DiagnosticUpdatable + */ +public abstract class AbstractTablePanel extends JPanel implements DiagnosticUpdatable { + // Static variables. + private static final long serialVersionUID = 0L; + + // Table models. + private final TableTextModel localModel; + private final TableTextModel globalModel; + + // Components. + private JTable localTable; + private JLabel localHeader; + private JTable globalTable; + private JLabel globalHeader; + private Dimension defaultPrefSize = new Dimension(0, 0); + private Dimension userPrefSize = null; + + // Table model mappings. + private static final int COL_TITLE = 0; + private static final int COL_VALUE = 1; + + /** + * Instantiates an <code>AbstractTablePanel</code> with a number + * of rows equal to the length of the argument array. Note that + * the panel requires that there be at least one row. + * @param rowNames - An array of <code>String</code> objects that + * are to be displayed for the names of the table rows. + */ + public AbstractTablePanel(String[] rowNames) { + // Initialize the table models. They should have two columns + // (one for values and one for headers) and a number of rows + // equal to the number of row names. + localModel = new TableTextModel(rowNames.length, 2); + globalModel = new TableTextModel(rowNames.length, 2); + + // Initialize the titles. + for(int i = 0; i < rowNames.length; i++) { + localModel.setValueAt(rowNames[i], i, COL_TITLE); + globalModel.setValueAt(rowNames[i], i, COL_TITLE); + } + updatePanel(null); + + // Define the panel layout. + //SpringLayout layout = new SpringLayout(); + setLayout(null); + + // Create header labels for the tables. + localHeader = new JLabel("Local Statistics"); + localHeader.setHorizontalAlignment(JLabel.CENTER); + add(localHeader); + + globalHeader = new JLabel("Run Statistics"); + globalHeader.setHorizontalAlignment(JLabel.CENTER); + add(globalHeader); + + // Create JTable objects to display the data. + localTable = new JTable(localModel); + localTable.setRowSelectionAllowed(false); + localTable.setColumnSelectionAllowed(false); + localTable.setCellSelectionEnabled(false); + add(localTable); + + globalTable = new JTable(globalModel); + globalTable.setRowSelectionAllowed(false); + globalTable.setColumnSelectionAllowed(false); + globalTable.setCellSelectionEnabled(false); + add(globalTable); + + // Track when the component changes size and reposition the + // components accordingly. + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { positionComponents(); } + }); + + // Define the component preferred size. + defaultPrefSize.width = localTable.getPreferredSize().width + + ComponentUtils.hinternal + globalTable.getPreferredSize().width; + defaultPrefSize.height = localTable.getPreferredSize().height + + ComponentUtils.vinternal + globalTable.getPreferredSize().height; + } + + @Override + public Dimension getPreferredSize() { + // If there is a user-specified preferred size, return that. + if(userPrefSize == null) { return defaultPrefSize; } + + // Otherwise, return the default calculated preferred size. + else { return userPrefSize; } + } + + @Override + public void setBackground(Color bg) { + // Set the base component background. + super.setBackground(bg); + + // If the components have been initialized, pass the background + // color change to them as appropriate. Note that the tables + // will always retain the same background color. + if(localTable != null) { + // Set the header backgrounds. + localHeader.setBackground(bg); + globalHeader.setBackground(bg); + } + } + + @Override + public void setFont(Font font) { + // Set the base component font. + super.setFont(font); + + // If the components have been initialized, pass the font change + // to them as appropriate. + if(localTable != null) { + // Set the table fonts. + localTable.setFont(font); + globalTable.setFont(font); + + // Set the header fonts. + Font headerFont = font.deriveFont(Font.BOLD, (float) Math.ceil(font.getSize2D() * 1.3)); + localHeader.setFont(headerFont); + globalHeader.setFont(headerFont); + } + } + + @Override + public void setForeground(Color fg) { + // Set the base component foreground. + super.setForeground(fg); + + // If the components have been initialized, pass the foreground + // color change to them as appropriate. Note that the tables + // will always retain the same foreground color. + if(localTable != null) { + // Set the header foregrounds. + localHeader.setForeground(fg); + globalHeader.setForeground(fg); + } + } + + @Override + public void setPreferredSize(Dimension preferredSize) { + userPrefSize = preferredSize; + } + + /** + * Sets the value of the indicated row for the global statistical + * table. + * @param rowIndex - The row. + * @param value - The new value. + */ + protected void setGlobalRowValue(int rowIndex, String value) { + globalModel.setValueAt(value, rowIndex, COL_VALUE); + } + + /** + * Sets the value of the indicated row for the local statistical + * table. + * @param rowIndex - The row. + * @param value - The new value. + */ + protected void setLocalRowValue(int rowIndex, String value) { + localModel.setValueAt(value, rowIndex, COL_VALUE); + } + + /** + * Repositions the components to the correct places on the parent + * <code>JPanel</code>. This should be run whenever the panel + * changes size. + */ + private void positionComponents() { + // Do not update if the components have not been initialized. + if(localHeader == null) { return; } + + // The local components get the left half of the panel and the + // global components the right. Find half of the panel width, + // accounting for the internal spacing. This is an internal + // component, so it does not employ additional spacing between + // itself and the parent component's edges. + int compWidth = (getWidth() - 10) / 2; + + // If there is any width remaining, it goes to the spacing. + int horizontal = ComponentUtils.hinternal + (getWidth() - 10) % 2; + + // Place the header labels. These are given their preferred + // height. Note that this means a very small panel may cut off + // some of the components. First, get the preferred height of + // the label with the larger preferred height. These should be + // the same thing, but just in case... + int labelHeight = localHeader.getPreferredSize().height; + if(labelHeight < globalHeader.getPreferredSize().height) { + labelHeight = globalHeader.getPreferredSize().height; + } + + // Set the label sizes and positions. + localHeader.setBounds(0, 0, compWidth, labelHeight); + globalHeader.setLocation(ComponentUtils.getNextX(localHeader, horizontal), 0); + globalHeader.setSize(compWidth, labelHeight); + + // The tables go under their respective labels and should fill + // the remainder of the label height. + int tableY = ComponentUtils.getNextY(localHeader, ComponentUtils.vinternal); + localTable.setBounds(0, tableY, compWidth, localTable.getPreferredSize().height); + globalTable.setBounds(globalHeader.getX(), tableY, compWidth, globalTable.getPreferredSize().height); + } +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ClusterTablePanel.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ClusterTablePanel.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ClusterTablePanel.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,111 @@ +package org.hps.users.kmccarty.diagpanel; + +import org.hps.users.kmccarty.DiagSnapshot; + +/** + * Class <code>ClusterTablePanel</code> is an implementation of class + * <code>AbstractTablePanel</code> for cluster statistical data.<br/> + * <br/> + * This implements the interface <code>DiagnosticUpdatable</code>. + * + * @author Kyle McCarty <[log in to unmask]> + * @see AbstractTablePanel + */ +public class ClusterTablePanel extends AbstractTablePanel { + // Static variables. + private static final long serialVersionUID = 0L; + private static final String[] TABLE_TITLES = { "Recon Clusters:", "SSP Clusters", "Matched Clusters", + "Failed (Position)", "Failed (Energy)", "Failed (Hit Count)" }; + + // Table model mappings. + private static final int ROW_RECON_COUNT = 0; + private static final int ROW_SSP_COUNT = 1; + private static final int ROW_MATCHED = 2; + private static final int ROW_FAILED_POSITION = 3; + private static final int ROW_FAILED_ENERGY = 4; + private static final int ROW_FAILED_HIT_COUNT = 5; + + /** + * Instantiate a new <code>ClusterTablePanel</code>. + */ + public ClusterTablePanel() { super(TABLE_TITLES); } + + @Override + public void updatePanel(DiagSnapshot snapshot) { + // If the snapshot is null, all values should be "N/A." + if(snapshot == null) { + // Output cluster count data. + String scalerNullValue = "---"; + setLocalRowValue(ROW_RECON_COUNT, scalerNullValue); + setLocalRowValue(ROW_SSP_COUNT, scalerNullValue); + setGlobalRowValue(ROW_RECON_COUNT, scalerNullValue); + setGlobalRowValue(ROW_SSP_COUNT, scalerNullValue); + + // Output the tracked statistical data. + String percentNullValue = "--- / --- (---%)"; + setLocalRowValue(ROW_MATCHED, percentNullValue); + setLocalRowValue(ROW_FAILED_POSITION, percentNullValue); + setLocalRowValue(ROW_FAILED_ENERGY, percentNullValue); + setLocalRowValue(ROW_FAILED_HIT_COUNT, percentNullValue); + setGlobalRowValue(ROW_MATCHED, percentNullValue); + setGlobalRowValue(ROW_FAILED_POSITION, percentNullValue); + setGlobalRowValue(ROW_FAILED_ENERGY, percentNullValue); + setGlobalRowValue(ROW_FAILED_HIT_COUNT, percentNullValue); + } + + // Otherwise, populate the table with the diagnostic data. + else { + /* + * This is disabled until the snapshot object is stable and + * is subject to change. It will not work if enabled now. + // Get the largest number of digits in any of the values. + int mostDigits = 0; + for(int valueID = 0; valueID < DiagSnapshot.CL_BANK_SIZE; valueID++) { + int localDigits = ComponentUtils.getDigits(snapshot.getClusterValue(LOCAL, valueID)); + int globalDigits = ComponentUtils.getDigits(snapshot.getClusterValue(GLOBAL, valueID)); + mostDigits = ComponentUtils.max(mostDigits, localDigits, globalDigits); + } + + // Put the number of reconstructed and SSP clusters into + // the tables. + int[] clusterValue = { + snapshot.getClusterValue(LOCAL, DiagSnapshot.CL_VALUE_RECON_CLUSTERS), + snapshot.getClusterValue(LOCAL, DiagSnapshot.CL_VALUE_SSP_CLUSTERS), + snapshot.getClusterValue(GLOBAL, DiagSnapshot.CL_VALUE_RECON_CLUSTERS), + snapshot.getClusterValue(GLOBAL, DiagSnapshot.CL_VALUE_SSP_CLUSTERS) + }; + String countFormat = "%" + mostDigits + "d"; + setLocalRowValue(ROW_RECON_COUNT, String.format(countFormat, clusterValue[0])); + setLocalRowValue(ROW_SSP_COUNT, String.format(countFormat, clusterValue[1])); + setGlobalRowValue(ROW_RECON_COUNT, String.format(countFormat, clusterValue[2])); + setGlobalRowValue(ROW_SSP_COUNT, String.format(countFormat, clusterValue[3])); + + // Output the tracked statistical data. + int total; + String percentFormat = "%" + mostDigits + "d / %" + mostDigits + "d (%7.3f)"; + int[] statValue = { + snapshot.getClusterValue(DiagSnapshot.TYPE_LOCAL, DiagSnapshot.CL_VALUE_MATCHED), + snapshot.getClusterValue(DiagSnapshot.TYPE_LOCAL, DiagSnapshot.CL_VALUE_FAIL_POSITION), + snapshot.getClusterValue(DiagSnapshot.TYPE_LOCAL, DiagSnapshot.CL_VALUE_FAIL_ENERGY), + snapshot.getClusterValue(DiagSnapshot.TYPE_LOCAL, DiagSnapshot.CL_VALUE_FAIL_HIT_COUNT), + snapshot.getClusterValue(DiagSnapshot.TYPE_GLOBAL, DiagSnapshot.CL_VALUE_MATCHED), + snapshot.getClusterValue(DiagSnapshot.TYPE_GLOBAL, DiagSnapshot.CL_VALUE_FAIL_POSITION), + snapshot.getClusterValue(DiagSnapshot.TYPE_GLOBAL, DiagSnapshot.CL_VALUE_FAIL_ENERGY), + snapshot.getClusterValue(DiagSnapshot.TYPE_GLOBAL, DiagSnapshot.CL_VALUE_FAIL_HIT_COUNT) + }; + + total = snapshot.getClusterValue(DiagSnapshot.TYPE_LOCAL, DiagSnapshot.CL_VALUE_RECON_CLUSTERS); + setLocalRowValue(ROW_MATCHED, String.format(percentFormat, statValue[0], total, 100.0 * statValue[0] / total)); + setLocalRowValue(ROW_FAILED_POSITION, String.format(percentFormat, statValue[1], total, 100.0 * statValue[1] / total)); + setLocalRowValue(ROW_FAILED_ENERGY, String.format(percentFormat, statValue[2], total, 100.0 * statValue[2] / total)); + setLocalRowValue(ROW_FAILED_HIT_COUNT, String.format(percentFormat, statValue[3], total, 100.0 * statValue[3] / total)); + + total = snapshot.getClusterValue(DiagSnapshot.TYPE_GLOBAL, DiagSnapshot.CL_VALUE_RECON_CLUSTERS); + setGlobalRowValue(ROW_MATCHED, String.format(percentFormat, statValue[4], total, 100.0 * statValue[4] / total)); + setGlobalRowValue(ROW_FAILED_POSITION, String.format(percentFormat, statValue[5], total, 100.0 * statValue[5] / total)); + setGlobalRowValue(ROW_FAILED_ENERGY, String.format(percentFormat, statValue[6], total, 100.0 * statValue[6] / total)); + setGlobalRowValue(ROW_FAILED_HIT_COUNT, String.format(percentFormat, statValue[7], total, 100.0 * statValue[7] / total)); + */ + } + } +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ComponentUtils.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ComponentUtils.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/ComponentUtils.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,106 @@ +package org.hps.users.kmccarty.diagpanel; + +import java.awt.Component; + +import org.hps.users.kmccarty.TriggerDiagnosticUtil; + +/** + * Class <code>ComponentUtils</code> is a list of utility methods used + * by the trigger diagnostic GUI. + * + * @author Kyle McCarty <[log in to unmask]> + */ +class ComponentUtils { + /** The default spacing used between a horizontal edge of one + * component and the horizontal edge of another. */ + public static final int hinternal = 10; + /** The default spacing used between a vertical edge of one + * component and the vertical edge of another. */ + public static final int vinternal = 10; + /** The default spacing used between a horizontal edge of one + * component and the edge of its parent component. */ + public static final int hexternal = 0; + /** The default spacing used between a vertical edge of one + * component and the edge of its parent component. */ + public static final int vexternal = 0; + + /** + * 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 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; + } + + /** + * 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; + } +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/DiagnosticUpdatable.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/DiagnosticUpdatable.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/DiagnosticUpdatable.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,22 @@ +package org.hps.users.kmccarty.diagpanel; + +import org.hps.users.kmccarty.DiagSnapshot; + +/** + * Interface <code>DiagnosticUpdatable</code> defines a class of objects + * that can be updated with information from a trigger diagnostic driver. + * They can take snapshots of the driver results and use this in order to + * alter their displayed or constituent values. + * + * @author Kyle McCarty <[log in to unmask]> + * @see DiagSnapshot + */ +public interface DiagnosticUpdatable { + /** + * Updates the object with information from the trigger diagnostic + * snapshot in the argument. + * @param snapshot - The snapshot containing information with which + * to update the object. + */ + public void updatePanel(DiagSnapshot snapshot); +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/TableTextModel.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/TableTextModel.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/diagpanel/TableTextModel.java Tue Mar 3 16:01:55 2015 @@ -0,0 +1,103 @@ +package org.hps.users.kmccarty.diagpanel; + +import javax.swing.table.AbstractTableModel; + +/** + * Class <code>TableTextModel</code> is a simple implementation of + * <code>AbstractTableModel</code> that supports a definable number + * of rows and columns which must be populated with <code>String</code> + * data. + * + * @author Kyle McCarty <[log in to unmask]> + */ +public class TableTextModel extends AbstractTableModel { + // Serial UID. + private static final long serialVersionUID = 0L; + + // Stored values. + private final int rows, columns; + private final String[][] values; + + /** + * Instantiates a new <code>TableTextModel</code> with the indicated + * number of rows and columns. + * @param rows - The number of rows. + * @param columns - The number of columns. + */ + public TableTextModel(int rows, int columns) { + // Make sure that the arguments for rows and columns are valid. + if(rows < 1) { + throw new IllegalArgumentException("TableTextModel must have at least one row."); + } else if(columns < 1) { + throw new IllegalArgumentException("TableTextModel must have at least one column."); + } + + // Define the number of rows and columns. + this.rows = rows; + this.columns = columns; + + // Instantiate the data storage array. + values = new String[rows][columns]; + } + + @Override + public int getRowCount() { return rows; } + + @Override + public int getColumnCount() { return columns; } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + // Ensure that the value is within the allowed range. + validateIndex(rowIndex, columnIndex); + + // Return the value. + return values[rowIndex][columnIndex]; + } + + @Override + public void setValueAt(Object value, int rowIndex, int columnIndex) { + // If the object is a string, pass it to the preferred handler. + // This can also be performed if the value is null. + if(value == null || value instanceof String) { + setValueAt((String) value, rowIndex, columnIndex); + } + + // Otherwise, cast the object to a string and use that instead. + else { setValueAt(value.toString(), rowIndex, columnIndex); } + } + + /** + * Sets the text for the indicated column and row of the table. + * @param value - The new text. + * @param rowIndex - The row. + * @param columnIndex - The column. + * @throws IndexOutOfBoundsException Occurs if the row and column + * are not a valid member of table model. + */ + public void setValueAt(String value, int rowIndex, int columnIndex) throws IndexOutOfBoundsException { + // Ensure that the value is within the allowed range. + validateIndex(rowIndex, columnIndex); + + // Set the value. + values[rowIndex][columnIndex] = value; + } + + /** + * Checks to make sure that a given row/column pointer refers to + * an extant position in the data array. In the event that the row + * and column values are not valid, an <code>IndexOutOfBounds</code> + * exception is thrown. + * @param rowIndex - The row index. + * @param columnIndex - The column index. + * @throws IndexOutOfBoundsException Occurs if the row and column + * are not a valid member of the data array. + */ + private void validateIndex(int rowIndex, int columnIndex) throws IndexOutOfBoundsException { + if(rowIndex < 0 || rowIndex >= getRowCount()) { + throw new IndexOutOfBoundsException(String.format("Row index %d is out of bounds.", rowIndex)); + } else if(columnIndex < 0 || columnIndex >= getColumnCount()) { + throw new IndexOutOfBoundsException(String.format("Column index %d is out of bounds.", columnIndex)); + } + } +}