Author: [log in to unmask] Date: Mon May 11 19:09:31 2015 New Revision: 2957 Log: Added driver for performing trigger cuts on a readout file, such as data output from a run. This driver assumes that each event contains a wide range (at least 100 ns or so) of clusters and thusly does not need to retain clusters across events for proper management of the time coincidence cut. Added: java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/ReadoutTrigger.java Added: java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/ReadoutTrigger.java ============================================================================= --- java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/ReadoutTrigger.java (added) +++ java/trunk/ecal-readout-sim/src/main/java/org/hps/readout/ecal/ReadoutTrigger.java Mon May 11 19:09:31 2015 @@ -0,0 +1,312 @@ +package org.hps.readout.ecal; + +import hep.aida.IHistogram1D; +import hep.aida.IHistogram2D; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.hps.recon.ecal.triggerbank.TriggerModule; +import org.lcsim.event.Cluster; +import org.lcsim.event.EventHeader; +import org.lcsim.util.Driver; +import org.lcsim.util.aida.AIDA; + +/** + * Creates distributions from <code>Cluster</code> objects. This is + * intended to be used on clusters reconstructed from FADC data from + * the hardware readout and should not be used for Monte Carlo. + * + * @author Kyle McCarty <[log in to unmask]> + */ +public class ReadoutTrigger extends Driver { + // Define settable parameters. + private double energySlopeParamF = 0.0055; + private String clusterCollectionName = "EcalClusters"; + + // Define internal variables. + private TriggerModule trigger = new TriggerModule(); + + // Define output plots. + private static final int NO_CUTS = 0; + private static final int ALL_CUTS = 1; + private AIDA aida = AIDA.defaultInstance(); + private IHistogram1D[] clusterSeedEnergy; + private IHistogram1D[] clusterHitCount; + private IHistogram1D[] clusterTotalEnergy; + private IHistogram1D[] clusterTime; + private IHistogram1D[] pairEnergySum; + private IHistogram1D[] pairEnergyDifference; + private IHistogram1D[] pairCoplanarity; + private IHistogram1D[] pairEnergySlope; + private IHistogram1D[] pairTime; + private IHistogram1D[] pairCoincidence; + private IHistogram2D[] clusterDistribution; + private IHistogram2D[] pairEnergySum2D; + private IHistogram2D[] pairEnergySlope2D; + + /** + * Instantiates cluster plots. + */ + @Override + public void startOfData() { + // Define plot type names. + String[] plotType = new String[2]; + plotType[NO_CUTS] = ""; + plotType[ALL_CUTS] = " (Passed All Cuts)"; + + // Define plot type directories. + String[] plotDir = new String[2]; + plotDir[NO_CUTS] = "NoCuts/"; + plotDir[ALL_CUTS] = "PassedAll/"; + + // Instantiate the plots. + for(int i = 0; i < 2; i++) { + System.out.println(plotDir[i] + "Cluster Seed Energy" + plotType[i]); + clusterSeedEnergy[i] = aida.histogram1D(plotDir[i] + "Cluster Seed Energy" + plotType[i], 88, 0.0, 1.1); + clusterSeedEnergy[i].annotation().addItem("xAxisLabel", "Seed Energy (GeV)"); + clusterSeedEnergy[i].annotation().addItem("yAxisLabel", "Count"); + + clusterHitCount[i] = aida.histogram1D(plotDir[i] + "Cluster Hit Count" + plotType[i], 9, 0.5, 9.5); + clusterHitCount[i].annotation().addItem("xAxisLabel", "Hit Count"); + clusterHitCount[i].annotation().addItem("yAxisLabel", "Count"); + + clusterTotalEnergy[i] = aida.histogram1D(plotDir[i] + "Cluster Total Energy" + plotType[i], 88, 0.0, 1.1); + clusterTotalEnergy[i].annotation().addItem("xAxisLabel", "Cluster Energy (GeV)"); + clusterTotalEnergy[i].annotation().addItem("yAxisLabel", "Count"); + + clusterTime[i] = aida.histogram1D(plotDir[i] + "Cluster Time" + plotType[i], 100, 0.0, 400); + clusterTime[i].annotation().addItem("xAxisLabel", "Cluster Time (ns)"); + clusterTime[i].annotation().addItem("yAxisLabel", "Count"); + + pairEnergySum[i] = aida.histogram1D(plotDir[i] + "Pair Energy Sum" + plotType[i], 88, 0.0, 2.2); + pairEnergySum[i].annotation().addItem("xAxisLabel", "Energy Sum (GeV)"); + pairEnergySum[i].annotation().addItem("yAxisLabel", "Count"); + + pairEnergyDifference[i] = aida.histogram1D(plotDir[i] + "Pair Energy Difference" + plotType[i], 88, 0.0, 1.1); + pairEnergyDifference[i].annotation().addItem("xAxisLabel", "Energy Difference (GeV)"); + pairEnergyDifference[i].annotation().addItem("yAxisLabel", "Count"); + + pairCoplanarity[i] = aida.histogram1D(plotDir[i] + "Pair Coplanarity" + plotType[i], 180, 0.0, 180.0); + pairCoplanarity[i].annotation().addItem("xAxisLabel", "Coplanarity Angle (Degrees)"); + pairCoplanarity[i].annotation().addItem("yAxisLabel", "Count"); + + pairEnergySlope[i] = aida.histogram1D(plotDir[i] + "Pair Energy Slope" + plotType[i], 200, 0.0, 4.0); + pairEnergySlope[i].annotation().addItem("xAxisLabel", "Energy Slope (GeV)"); + pairEnergySlope[i].annotation().addItem("yAxisLabel", "Count"); + + pairTime[i] = aida.histogram1D(plotDir[i] + "Pair Time" + plotType[i], 100, 0.0, 400); + pairTime[i].annotation().addItem("xAxisLabel", "Cluster Time (ns)"); + pairTime[i].annotation().addItem("yAxisLabel", "Count"); + + pairCoincidence[i] = aida.histogram1D(plotDir[i] + "Pair Coincidence" + plotType[i], 8, 0.0, 32); + pairCoincidence[i].annotation().addItem("xAxisLabel", "Coincidence Time (ns)"); + pairCoincidence[i].annotation().addItem("yAxisLabel", "Count"); + + clusterDistribution[i] = aida.histogram2D(plotDir[i] + "Cluster Seed Distribution" + plotType[i], 46, -23, 23, 11, -5.5, 5.5); + clusterDistribution[i].annotation().addItem("xAxisLabel", "x-Index"); + clusterDistribution[i].annotation().addItem("yAxisLabel", "y-Index"); + + pairEnergySum2D[i] = aida.histogram2D(plotDir[i] + "Pair Energy Sum 2D" + plotType[i], 88, 0.0, 2.2, 88, 0.0, 2.2); + pairEnergySum2D[i].annotation().addItem("xAxisLabel", "E1"); + pairEnergySum2D[i].annotation().addItem("yAxisLabel", "E2"); + + pairEnergySlope2D[i] = aida.histogram2D(plotDir[i] + "Pair Energy Slope 2D" + plotType[i], 88, 0.0, 1.1, 200, 0.0, 400); + pairEnergySlope2D[i].annotation().addItem("xAxisLabel", "E1"); + pairEnergySlope2D[i].annotation().addItem("yAxisLabel", "E2"); + } + } + + /** + * Produces both uncut and cut distributions from clusters. + */ + @Override + public void process(EventHeader event) { + // Check for a collection of clusters. + if(event.hasCollection(Cluster.class, clusterCollectionName)) { + // Get the list of clusters. + List<Cluster> clusters = event.get(Cluster.class, clusterCollectionName); + + // Track which clusters have already been plotted. + Set<Cluster> plottedClustersUncut = new HashSet<Cluster>(clusters.size()); + Set<Cluster> plottedClustersCut = new HashSet<Cluster>(clusters.size()); + + // Populate a list of cluster pairs. + List<Cluster[]> pairs = getClusterPairs(clusters); + + // Process all cluster pairs. + pairLoop: + for(Cluster[] pair : pairs) { + // Get the x and y indices for each cluster in the pair. + int[] ix = { pair[0].getCalorimeterHits().get(0).getIdentifierFieldValue("ix"), + pair[1].getCalorimeterHits().get(0).getIdentifierFieldValue("ix") }; + int[] iy = { pair[0].getCalorimeterHits().get(0).getIdentifierFieldValue("iy"), + pair[1].getCalorimeterHits().get(0).getIdentifierFieldValue("iy") }; + + // Iterate over the clusters in the pair and plot the + // cluster singles distributions. + for(int clusterIndex = 0; clusterIndex < 2; clusterIndex++) { + // Only plot cluster singles distributions for + // clusters if they have not already been plotted. + // Note that this is needed because the same cluster + // can appear across multiple pairs. + if(!plottedClustersUncut.contains(pair[clusterIndex])) { + clusterSeedEnergy[NO_CUTS].fill(TriggerModule.getValueClusterSeedEnergy(pair[clusterIndex])); + clusterTotalEnergy[NO_CUTS].fill(TriggerModule.getValueClusterTotalEnergy(pair[clusterIndex])); + clusterHitCount[NO_CUTS].fill(TriggerModule.getValueClusterHitCount(pair[clusterIndex])); + clusterDistribution[NO_CUTS].fill(ix[clusterIndex], iy[clusterIndex]); + clusterTime[NO_CUTS].fill(pair[clusterIndex].getCalorimeterHits().get(0).getTime()); + plottedClustersUncut.add(pair[clusterIndex]); + } + } + + // Plot the cluster pair distributions. + pairEnergySum[NO_CUTS].fill(TriggerModule.getValueEnergySum(pair)); + pairEnergyDifference[NO_CUTS].fill(TriggerModule.getValueEnergyDifference(pair)); + pairEnergySlope[NO_CUTS].fill(TriggerModule.getValueEnergySlope(pair, energySlopeParamF)); + pairCoplanarity[NO_CUTS].fill(TriggerModule.getValueCoplanarity(pair)); + pairTime[NO_CUTS].fill(pair[1].getCalorimeterHits().get(0).getTime()); + pairCoincidence[NO_CUTS].fill(TriggerModule.getValueTimeCoincidence(pair)); + pairEnergySum2D[NO_CUTS].fill(pair[0].getEnergy(), pair[1].getEnergy()); + if(pair[0].getEnergy() < pair[1].getEnergy()) { + pairEnergySlope2D[NO_CUTS].fill(pair[0].getEnergy(), TriggerModule.getClusterDistance(pair[0])); + } else { + pairEnergySlope2D[NO_CUTS].fill(pair[1].getEnergy(), TriggerModule.getClusterDistance(pair[1])); + } + + // Perform the cluster singles cuts. + if(!(trigger.clusterHitCountCut(pair[0]) && trigger.clusterHitCountCut(pair[1]))) { + continue pairLoop; + } if(!(trigger.clusterTotalEnergyCut(pair[0]) && trigger.clusterTotalEnergyCut(pair[1]))) { + continue pairLoop; + } if(!(trigger.clusterSeedEnergyCut(pair[0]) && trigger.clusterSeedEnergyCut(pair[1]))) { + continue pairLoop; + } + + // Perform the cluster pair cuts. + if(!trigger.pairCoplanarityCut(pair)) { + continue pairLoop; + } if(!trigger.pairEnergyDifferenceCut(pair)) { + continue pairLoop; + } if(!trigger.pairEnergySlopeCut(pair)) { + continue pairLoop; + } if(!trigger.pairEnergySumCut(pair)) { + continue pairLoop; + } + + // Iterate over the clusters in the pair and plot the + // cluster singles distributions. + for(int clusterIndex = 0; clusterIndex < 2; clusterIndex++) { + // Only plot cluster singles distributions for + // clusters if they have not already been plotted. + // Note that this is needed because the same cluster + // can appear across multiple pairs. + if(!plottedClustersCut.contains(pair[clusterIndex])) { + clusterSeedEnergy[ALL_CUTS].fill(TriggerModule.getValueClusterSeedEnergy(pair[clusterIndex])); + clusterTotalEnergy[ALL_CUTS].fill(TriggerModule.getValueClusterTotalEnergy(pair[clusterIndex])); + clusterHitCount[ALL_CUTS].fill(TriggerModule.getValueClusterHitCount(pair[clusterIndex])); + clusterDistribution[ALL_CUTS].fill(ix[clusterIndex], iy[clusterIndex]); + clusterTime[ALL_CUTS].fill(pair[clusterIndex].getCalorimeterHits().get(0).getTime()); + plottedClustersCut.add(pair[clusterIndex]); + } + } + + // Plot the cluster pair distributions. + pairEnergySum[ALL_CUTS].fill(TriggerModule.getValueEnergySum(pair)); + pairEnergyDifference[ALL_CUTS].fill(TriggerModule.getValueEnergyDifference(pair)); + pairEnergySlope[ALL_CUTS].fill(TriggerModule.getValueEnergySlope(pair, energySlopeParamF)); + pairCoplanarity[ALL_CUTS].fill(TriggerModule.getValueCoplanarity(pair)); + pairTime[ALL_CUTS].fill(pair[1].getCalorimeterHits().get(0).getTime()); + pairCoincidence[ALL_CUTS].fill(TriggerModule.getValueTimeCoincidence(pair)); + pairEnergySum2D[ALL_CUTS].fill(pair[0].getEnergy(), pair[1].getEnergy()); + if(pair[0].getEnergy() < pair[1].getEnergy()) { + pairEnergySlope2D[ALL_CUTS].fill(pair[0].getEnergy(), TriggerModule.getClusterDistance(pair[0])); + } else { + pairEnergySlope2D[ALL_CUTS].fill(pair[1].getEnergy(), TriggerModule.getClusterDistance(pair[1])); + } + + } + } + } + + public void setClusterCollectionName(String clusterCollectionName) { + this.clusterCollectionName = clusterCollectionName; + } + + public void setEnergySlopeParamF(double energySlopeParamF) { + this.energySlopeParamF = energySlopeParamF; + trigger.setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, energySlopeParamF); + } + + public void setSeedEnergyLow(double value) { + trigger.setCutValue(TriggerModule.CLUSTER_SEED_ENERGY_LOW, value); + } + + public void setClusterEnergyLow(double value) { + trigger.setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, value); + } + + public void setClusterEnergyHigh(double value) { + trigger.setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, value); + } + + public void setHitCountLow(double value) { + trigger.setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, value); + } + + public void setEnergySumLow(double value) { + trigger.setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, value); + } + + public void setEnergySumHigh(double value) { + trigger.setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, value); + } + + public void setEnergyDifferenceHigh(double value) { + trigger.setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, value); + } + + public void setEnergySlopeLow(double value) { + trigger.setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, value); + } + + public void setCoplanarityHigh(double value) { + trigger.setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, value); + } + + public void setTimeCoincidence(double value) { + trigger.setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, value); + } + + /** + * Creates all top/bottom pairs from the event data. + * @param clusters - A list of clusters from which to form pairs. + * @return Returns a <code>List</code> collection that contains + * <code>Cluster</code> arrays of size two. + */ + private List<Cluster[]> getClusterPairs(List<Cluster> clusters) { + // Separate the clusters into top nad bottom clusters. + List<Cluster> topList = new ArrayList<Cluster>(); + List<Cluster> botList = new ArrayList<Cluster>(); + for(Cluster cluster : clusters) { + if(cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy") > 0) { + topList.add(cluster); + } else { + botList.add(cluster); + } + } + + // Create all possible top/bottom cluster pairs. + List<Cluster[]> pairList = new ArrayList<Cluster[]>(); + for(Cluster topCluster : topList) { + for(Cluster botCluster : botList) { + pairList.add(new Cluster[] { topCluster, botCluster }); + } + } + + // Return the pairs. + return pairList; + } +}