Author: [log in to unmask] Date: Tue Oct 11 21:48:17 2016 New Revision: 4509 Log: Removed three unused drivers and added a driver to skip all drivers in the event chain unless certain TI bits are set and a driver that produces basic trigger cut distributions. Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/SimpleTriggerPlotsDriver.java (with props) java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerBitFilterDriver.java (with props) Removed: java/trunk/users/src/main/java/org/hps/users/kmccarty/ClusterAnalysisDriver.java java/trunk/users/src/main/java/org/hps/users/kmccarty/FADCAnalysisDriver.java java/trunk/users/src/main/java/org/hps/users/kmccarty/ParticleMCAnalysisDriver.java Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/SimpleTriggerPlotsDriver.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/SimpleTriggerPlotsDriver.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/SimpleTriggerPlotsDriver.java Tue Oct 11 21:48:17 2016 @@ -0,0 +1,351 @@ +package org.hps.users.kmccarty; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import org.hps.record.daqconfig.ConfigurationManager; +import org.hps.record.daqconfig.DAQConfig; +import org.hps.record.triggerbank.TriggerModule; +import org.lcsim.event.CalorimeterHit; +import org.lcsim.event.Cluster; +import org.lcsim.event.EventHeader; +import org.lcsim.util.Driver; +import org.lcsim.util.aida.AIDA; + +/** + * Driver <code>SimpleTriggerPlotsDriver</code> produces distributions + * for all of the singles and pair trigger cuts from clusters found in + * a user-defined LCIO collection. + * <br/><br/> + * Clusters are filtered to remove those clusters from the collection + * found in the "pulse-clipping region," defined as [nsb, windowWidth - + * nsa]. This is done because in data, readout does not include pulses + * past the start and end of the readout window, so clusters occurring + * such that their integration window would exceed these bounds will + * produce lower-than-expected energies. While not relevant for Monte + * Carlo, the same check is applied to ensure that the data plotted is + * comparable. + * <br/><br/> + * The driver requires the window width and the number of integration + * samples (both before and after the threshold crossing) to be defined + * in order to check for pulse-clipping. It also requires that the + * energy sum conversion parameter be defined for calculating the energy + * sum cut value. Lastly, it requires an LCIO cluster collection to be + * defined. If preferred, all of these except the collection name may + * be passed to the DAQ configuration manager instead of using the + * user-defined values. + * <br/><br/> + * This driver does not filter based on trigger type. For data, it is + * suggested that a filter be added upstream or that a skim be used to + * account for this, if only data from a specific trigger is desired. + * + * @author Kyle McCarty <[log in to unmask]> + */ +public class SimpleTriggerPlotsDriver extends Driver { + private int nsa = Integer.MIN_VALUE; + private int nsb = Integer.MIN_VALUE; + private int events = 0; + private int windowWidth = Integer.MIN_VALUE; + private boolean useDAQConfig = false; + private double energySlopeParam = Double.NaN; + private String clusterCollectionName = null; + + // Define cluster type and cut type reference variables. + private static final int CLUSTER_TOTAL_ENERGY = 0; + private static final int CLUSTER_SEED_ENERGY = 1; + private static final int CLUSTER_HIT_COUNT = 2; + private static final int PAIR_ENERGY_SUM = 3; + private static final int PAIR_ENERGY_DIFF = 4; + private static final int PAIR_ENERGY_SLOPE = 5; + private static final int PAIR_COPLANARITY = 6; + private static final int PAIR_TIME_COINCIDENCE = 7; + private static final String[] TRIGGER_CUT_NAME = { + "Cluster Total Energy", "Cluster Seed Energy", "Cluster Hit Count", + "Pair Energy Sum", "Pair Energy Difference", "Pair Energy Slope", + "Pair Coplanarity", "Pair Time Coincidence" + }; + + // Define the bin settings for the efficiency plots. + private int[] bins = new int[8]; + private double[] xMax = { + 2.200, // Cluster energy, xMax = 2.2 GeV + 2.200, // Seed energy, xMax = 2.2 GeV + 9.5, // Hit count, xMax = 9.5 hits + 2.200, // Energy sum, xMax = 2.2 GeV + 2.200, // Energy difference, xMax = 2.2 GeV + 4.000, // Energy slope, xMax = 4.0 GeV + 180.0, // Coplanarity, xMax = 180 degrees + 30.0 // Time coincidence, xMax = 30 ns + }; + private double[] binSize = { + 0.050, // Cluster energy, binSize = 50 MeV + 0.050, // Seed energy, binSize = 50 MeV + 1, // Hit count, binSize = 1 hit + 0.050, // Energy sum, binSize = 50 MeV + 0.050, // Energy difference, binSize = 50 MeV + 0.050, // Energy slope, binSize = 50 MeV + 5, // Coplanarity, binSize = 5 degrees + 2 // Time coincidence, binSize = 2 ns + }; + + // Define plotting objects. + private AIDA aida = AIDA.defaultInstance(); + private static final String BASE_FOLDER_NAME = "Simple Trigger Cut Plots/"; + + /** + * Runs at the end of the run. Calculates the total event time + * processed and scales all trigger cut plots by this value to + * convert their y-axis scale to units of Hertz. + */ + @Override + public void endOfData() { + // Determine the total amount of time that was processed. This + // is calculated by multiplying the number of events by the size + // of the readout window that is not pulse-clipped. + double scalingFactor = 1.0 / (events * (windowWidth - nsa - nsb)); + + // Scale each trigger plot by the amount of time it represents + // to convert the y-axis scale to units of Hertz. + for(int triggerCut = CLUSTER_TOTAL_ENERGY; triggerCut <= PAIR_TIME_COINCIDENCE; triggerCut++) { + aida.histogram1D(getTriggerPlotName(triggerCut)).scale(scalingFactor); + } + } + + /** + * Runs at the beginning of the run. Instantiates all trigger cut + * plots as well as the DAQ configuration manager, if it is enabled. + * Also makes sure that any necessary parameters are defined. + */ + @Override + public void startOfData() { + // A cluster collection name must be defined. + if(clusterCollectionName == null) { + throw new IllegalArgumentException("A cluster collection name must be defined."); + } + + // If the DAQ configuration is not to be used, all of the window + // and trigger parameters must be defined manually. + if(!useDAQConfig) { + // Require that each parameter be defined. + if(nsa <= 0) { + throw new IllegalArgumentException("Parameter \"NSA\" must be defined and positive."); + } if(nsb <= 0) { + throw new IllegalArgumentException("Parameter \"NSB\" must be defined and positive."); + } if(nsa <= 0) { + throw new IllegalArgumentException("Parameter \"Window Width\" must be defined and positive."); + } if(Double.isNaN(energySlopeParam)) { + throw new IllegalArgumentException("Parameter \"Energy Slope Conversion Parameter\" must be defined."); + } + + // Check that the window width is large enough to contain + // some time period where pulse-clipping is not an issue. + if(windowWidth - nsa - nsb <= 0) { + throw new IllegalArgumentException("Window width is smaller than integration window; no region is not pulse-clipped."); + } + } + + // Otherwise, wait for the DAQ configuration manager to receive + // the settings and set the values appropriately. + else { + ConfigurationManager.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + // Get the DAQ configuration. + DAQConfig daq = ConfigurationManager.getInstance(); + + // Load the DAQ settings from the configuration manager. + nsa = daq.getFADCConfig().getNSA(); + nsb = daq.getFADCConfig().getNSB(); + windowWidth = daq.getFADCConfig().getWindowWidth(); + energySlopeParam = daq.getSSPConfig().getPair2Config().getEnergySlopeCutConfig().getParameterF(); + } + }); + } + + // Instantiate plots for each trigger cut. + for(int triggerCut = CLUSTER_TOTAL_ENERGY; triggerCut <= PAIR_TIME_COINCIDENCE; triggerCut++) { + // Make sure that the maximum x-axis values for the efficiency + // plots are evenly divisible by the bin size. + if(Math.floor(1.0 * xMax[triggerCut] / binSize[triggerCut]) != (xMax[triggerCut] / binSize[triggerCut])) { + xMax[triggerCut] = Math.ceil(xMax[triggerCut] / binSize[triggerCut]) * binSize[triggerCut]; + } + + // Define the bin counts for each plot. + bins[triggerCut] = (int) Math.ceil(xMax[triggerCut] / binSize[triggerCut]); + + // Define the numerator, denominator, and ratio plots. + aida.histogram1D(getTriggerPlotName(triggerCut), bins[triggerCut], 0.0, bins[triggerCut] * binSize[triggerCut]); + } + } + + /** + * Runs each event. Collects all clusters from the indicated cluster + * collection and filters them to select only those within the time + * region safe from pulse-clipping. This is defined as [nsb, + * windowWidth - nsa]. All trigger cut values are then plotted for + * all clusters and cluster pairs within the filtered set. + * @param event - The object containing all event data. + */ + @Override + public void process(EventHeader event) { + // If the DAQ configuration is in use, only process the event + // if it has been instantiated. + if(useDAQConfig && !ConfigurationManager.isInitialized()) { + return; + } + + // Get the event GTP cluster collection. + if(!event.hasCollection(Cluster.class, clusterCollectionName)) { return; } + List<Cluster> clusters = event.get(Cluster.class, clusterCollectionName); + + // Filter the clusters to exclude those affected by the pulse + // clipping region. + List<Cluster> goodClusters = new ArrayList<Cluster>(); + for(Cluster cluster : clusters) { + if(isVerifiable(cluster, nsa, nsb, windowWidth)) { goodClusters.add(cluster); } + } + + // Populate the cluster singles plots. + for(Cluster cluster : goodClusters) { + aida.histogram1D(getTriggerPlotName(CLUSTER_SEED_ENERGY)).fill(TriggerModule.getValueClusterSeedEnergy(cluster)); + aida.histogram1D(getTriggerPlotName(CLUSTER_TOTAL_ENERGY)).fill(TriggerModule.getValueClusterTotalEnergy(cluster)); + aida.histogram1D(getTriggerPlotName(CLUSTER_HIT_COUNT)).fill(TriggerModule.getValueClusterHitCount(cluster)); + } + + // Get a list of all top/bottom cluster pairs. + List<Cluster[]> pairs = TriggerModule.getTopBottomPairs(clusters, Cluster.class); + + // Populate the cluster pair plots. + for(Cluster[] pair : pairs) { + aida.histogram1D(getTriggerPlotName(PAIR_ENERGY_SUM)).fill(TriggerModule.getValueEnergySum(pair)); + aida.histogram1D(getTriggerPlotName(PAIR_ENERGY_DIFF)).fill(TriggerModule.getValueEnergyDifference(pair)); + aida.histogram1D(getTriggerPlotName(PAIR_ENERGY_SLOPE)).fill(TriggerModule.getValueEnergySlope(pair, energySlopeParam)); + aida.histogram1D(getTriggerPlotName(PAIR_COPLANARITY)).fill(TriggerModule.getValueCoplanarity(pair)); + aida.histogram1D(getTriggerPlotName(PAIR_TIME_COINCIDENCE)).fill(TriggerModule.getValueTimeCoincidence(pair)); + } + + // Increment the number of processed events. + events++; + } + + /** + * Checks whether all of the hits in a cluster are within the safe + * region of the FADC output window. + * @param reconCluster - The cluster to check. + * @return Returns <code>true</code> if the cluster is safe and + * returns <code>false</code> otherwise. + */ + private static final boolean isVerifiable(Cluster reconCluster, int nsa, int nsb, int windowWidth) { + // Iterate over the hits in the cluster. + for(CalorimeterHit hit : reconCluster.getCalorimeterHits()) { + // Check that none of the hits are within the disallowed + // region of the FADC readout window. + if(hit.getTime() <= nsb || hit.getTime() >= (windowWidth - nsa)) { + return false; + } + + // Also check to make sure that the cluster does not have + // any negative energy hits. These are, obviously, wrong. + if(hit.getCorrectedEnergy() < 0.0) { + return false; + } + } + + // If all of the cluster hits pass the time cut, the cluster + // is valid. + return true; + } + + /** + * Forms the name for a specific cut's trigger plot. THis will always + * be the base folder name plus the name of the trigger cut. + * @param cutIndex - The index corresponding to the trigger cut. + * This should use one of the predefined cut indices from this class. + * @return Returns the plot name as a <code>String</code>. + */ + private static final String getTriggerPlotName(int cutIndex) { + return BASE_FOLDER_NAME + TRIGGER_CUT_NAME[cutIndex]; + } + + /** + * Sets the name of LCIO collection containing the clusters that + * are to be plotted. + * @param collection - The LCIO collection name. + */ + public void setClusterCollectionName(String collection) { + clusterCollectionName = collection; + } + + /** + * Specifies whether the parameters NSA, NSB, readout window width, + * and energy slope conversion parameter should be obtained from + * the DAQ configuration or if they should be obtained from user + * definitions. If the DAQ configuration is used, the energy slope + * conversion parameter is defined using the pair 1 trigger value. + * @param state - <code>true</code> means that all values will be + * acquired from the DAQ configuration. <code>false</code> means + * that user-defined values are expected. + */ + public void setUseDAQConfig(boolean state) { + useDAQConfig = state; + } + + /** + * Defines the number of integration samples after a threshold + * crossing used by the FADC. Note that this is only used if the + * DAQ configuration manager is disabled. + * @param value - The number of samples. + */ + public void setNsa(int value) { + nsa = value; + } + + /** + * Defines the number of integration samples before a threshold + * crossing used by the FADC. Note that this is only used if the + * DAQ configuration manager is disabled. + * @param value - The number of samples. + */ + public void setNsb(int value) { + nsb = value; + } + + /** + * Defines the size of the readout window. Note that this is only + * used if the DAQ configuration manager is disabled. + * @param value - The size of the readout window in nanoseconds. + */ + public void setWindowWidth(int value) { + windowWidth = value; + } + + /** + * Defines the conversion parameter used in the energy slope + * calculation. Note that this is only used if the DAQ configuration + * manager is disabled. + * @param value - The conversion parameter in units of GeV/mm. + */ + public void setEnergySlopeConversionParameter(double value) { + energySlopeParam = value; + } + + public void setClusterSeedEnergyXMax(double value) { xMax[CLUSTER_SEED_ENERGY] = value; } + public void setClusterTotalEnergyXMax(double value) { xMax[CLUSTER_TOTAL_ENERGY] = value; } + public void setClusterHitCountXMax(double value) { xMax[CLUSTER_HIT_COUNT] = value; } + public void setPairEnergySumXMax(double value) { xMax[PAIR_ENERGY_SUM] = value; } + public void setPairEnergyDiffXMax(double value) { xMax[PAIR_ENERGY_DIFF] = value; } + public void setPairEnergySlopeXMax(double value) { xMax[PAIR_ENERGY_SLOPE] = value; } + public void setPairCoplanarityXMax(double value) { xMax[PAIR_COPLANARITY] = value; } + public void setPairTimeCoincidenceXMax(double value) { xMax[PAIR_TIME_COINCIDENCE] = value; } + + public void setClusterSeedEnergyBinSize(double value) { binSize[CLUSTER_SEED_ENERGY] = value; } + public void setClusterTotalEnergyBinSize(double value) { binSize[CLUSTER_TOTAL_ENERGY] = value; } + public void setClusterHitCountBinSize(double value) { binSize[CLUSTER_HIT_COUNT] = value; } + public void setPairEnergySumBinSize(double value) { binSize[PAIR_ENERGY_SUM] = value; } + public void setPairEnergyDiffBinSize(double value) { binSize[PAIR_ENERGY_DIFF] = value; } + public void setPairEnergySlopeBinSize(double value) { binSize[PAIR_ENERGY_SLOPE] = value; } + public void setPairCoplanarityBinSize(double value) { binSize[PAIR_COPLANARITY] = value; } + public void setPairTimeCoincidenceBinSize(double value) { binSize[PAIR_TIME_COINCIDENCE] = value; } +} Added: java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerBitFilterDriver.java ============================================================================= --- java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerBitFilterDriver.java (added) +++ java/trunk/users/src/main/java/org/hps/users/kmccarty/TriggerBitFilterDriver.java Tue Oct 11 21:48:17 2016 @@ -0,0 +1,150 @@ +package org.hps.users.kmccarty; + +import java.util.List; + +import org.hps.record.triggerbank.AbstractIntData; +import org.hps.record.triggerbank.TIData; +import org.lcsim.event.EventHeader; +import org.lcsim.event.GenericObject; +import org.lcsim.util.Driver; + +/** + * Checks whether an event contains a TI bit flag, and if not, orders + * LCSim to ignore all subsequent drivers for this event. Note that + * this driver should be placed <i>before</i> any drivers that need + * to be skipped in the driver chain in order to work properly. + * + * @author Kyle McCarty <[log in to unmask]> + */ +public class TriggerBitFilterDriver extends Driver { + // Store the LCIO collection names. + private String bankCollectionName = null; + + // Store which triggers to filter. + private boolean selectPulser = false; + private boolean selectSingles0 = false; + private boolean selectSingles1 = false; + private boolean selectPair0 = false; + private boolean selectPair1 = false; + + /** + * Checks that the mandatory parameters have been set. + */ + @Override + public void startOfData() { + // Require that bank collection name be set. + if(bankCollectionName == null) { + throw new IllegalArgumentException("Trigger bank collection name must be defined."); + } + } + + /** + * Subsequent drivers should only be processed if the desired bit(s) + * is (are) active. Method checks to ensure that this condition is + * true, and if not, instructs LCSim to ignore subsequent drivers. + * @param event - The object containing event data. + */ + @Override + public void process(EventHeader event) { + // Get the TI bank. + TIData tiBank = null; + 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) == TIData.BANK_TAG) { + tiBank = new TIData(obj); + } + } + } + + // Determine if any of the selected trigger bits are present. + boolean passEvent = false; + if(selectPulser && tiBank.isPulserTrigger()) { + passEvent = true; + } else if(selectSingles0 && tiBank.isSingle0Trigger()) { + passEvent = true; + } else if(selectSingles1 && tiBank.isSingle1Trigger()) { + passEvent = true; + } else if(selectPair0 && tiBank.isPair0Trigger()) { + passEvent = true; + } else if(selectPair1 && tiBank.isPair1Trigger()) { + passEvent = true; + } + + // If any selected trigger bit is present, the event may proceed. + // Otherwise, do not process the event in any downstream drivers. + if(!passEvent) { throw new NextEventException(); } + } + + /** + * Sets the name of the LCIO collection containing the TI bank. + * @param collection - The LCIO collection name. + */ + public void setBankCollectionName(String collection) { + bankCollectionName = collection; + } + + /** + * Sets whether pulser triggers should be passed. + * @param state - <code>true</code> means this trigger type should + * be allowed through the filter. If the value is <code>false</code>, + * this type of trigger will not be selected, but will also not + * disallow the event from passing if another selected trigger type + * is present. + */ + public void setSelectPulserTriggers(boolean state) { + selectPulser = state; + } + + /** + * Sets whether singles 1 triggers should be passed. + * @param state - <code>true</code> means this trigger type should + * be allowed through the filter. If the value is <code>false</code>, + * this type of trigger will not be selected, but will also not + * disallow the event from passing if another selected trigger type + * is present. + */ + public void setSelectSingles0Triggers(boolean state) { + selectSingles0 = state; + } + + /** + * Sets whether singles 1 triggers should be passed. + * @param state - <code>true</code> means this trigger type should + * be allowed through the filter. If the value is <code>false</code>, + * this type of trigger will not be selected, but will also not + * disallow the event from passing if another selected trigger type + * is present. + */ + public void setSelectSingles1Triggers(boolean state) { + selectSingles1 = state; + } + + /** + * Sets whether pair 0 triggers should be passed. + * @param state - <code>true</code> means this trigger type should + * be allowed through the filter. If the value is <code>false</code>, + * this type of trigger will not be selected, but will also not + * disallow the event from passing if another selected trigger type + * is present. + */ + public void setSelectPair0Triggers(boolean state) { + selectPair0 = state; + } + + /** + * Sets whether pair 1 triggers should be passed. + * @param state - <code>true</code> means this trigger type should + * be allowed through the filter. If the value is <code>false</code>, + * this type of trigger will not be selected, but will also not + * disallow the event from passing if another selected trigger type + * is present. + */ + public void setSelectPair1Triggers(boolean state) { + selectPair1 = state; + } +}