Author: [log in to unmask] Date: Thu Aug 6 17:19:42 2015 New Revision: 3348 Log: Updated documentation for many ecal-recon drivers. Classes TDCData and HeadBankData require documentation still; I am not familiar enough with their function to provide it. Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterDriver.java Thu Aug 6 17:19:42 2015 @@ -1,24 +1,36 @@ package org.hps.recon.ecal.cluster; /** - * Class <code>GTPClusterDriver</code> instantiates an instance of - * the clustering algorithm framework for the Monte Carlo version - * of the GTP algorithm. This version assumes that events are equal - * to 2 ns beam bunches. The class also allows the seed energy threshold - * and cluster window to be set as well as whether or not the algorithm - * should employ an asymmetric time window and write out verbose debug - * text. + * Class <code>GTPClusterDriver</code> is an implementation of the + * <code>ClusterDriver</code> class that defines employs the readout + * variant of the GTP hardware clustering algorithm. Specifics on the + * behavior of this algorithm can be found in its documentation.<br/> + * <br/> + * <code>GTPClusterDriver</code> allows for all of the variable settings + * used by the GTP algorithm to be defined. It also can be set to + * "verbose" mode, where it will output detailed information on each + * event and the cluster forming process. This is disabled by default, + * but can be enabled for debugging purposes.<br/> + * <br/> + * <code>GTPClusterDriver</code> is designed to read from Monte Carlo + * data organized into 2-ns beam bunches. It can not be used for hardware + * readout data, or Monte Carlo formatted in this style. For this data, + * the <code>GTPOnlineClusterer</code> should be employed instead. * * @author Kyle McCarty <[log in to unmask]> * @author Jeremy McCormick <[log in to unmask]> * @see GTPClusterer */ public class GTPClusterDriver extends ClusterDriver { - // The GTP clustering algorithm. + /** An instance of the clustering algorithm object for producing + * cluster objects. */ private final GTPClusterer gtp; /** - * Instantiates a new <code>GTPClusterer</code>. + * Instantiates a new <code>GTPClusterer</code>, which will produce + * clusters using the GTP algorithm in the 2-ns beam bunch scheme. + * It will, by default, use a 50 MeV seed energy cut with +/- 2 a + * clock-cycle verification and inclusion window. */ public GTPClusterDriver() { clusterer = ClustererFactory.create("GTPClusterer"); @@ -27,66 +39,77 @@ } /** - * Sets whether hits should be added to a cluster from the entire - * cluster window or just the "future" hits, plus one clock-cycle - * of "past" hits as a safety buffer to account for time uncertainty. - * - * @param limitClusterRange - <code>true</code> indicates that - * the asymmetric clustering window should be used and <code> - * false</code> that the symmetric window should be used. + * Sets whether the behavior of the hit inclusion window with respect + * to the hit verification window. If set to <code>false</code>, + * both windows will be identical in size. Otherwise, the inclusion + * window will be equal in size after the seed hit, but encompass + * only one clock-cycle before the seed hit. This should be replaced + * by the method <code>setAsymmetricWindow</code>. + * @param limitClusterRange - <code>true</code> indicates that the + * asymmetric window should be used and <code>false</code> that it + * should not. */ @Deprecated public void setLimitClusterRange(boolean limitClusterRange) { - gtp.setLimitClusterRange(limitClusterRange); + gtp.setAsymmetricWindow(limitClusterRange); } /** - * Sets the number of clock-cycles (4 ns) before and after a hit - * in which the hit must be the maximum energy hit in its 3 x 3 - * window in order to be considered a seed hit and form a cluster. + * Sets the size of the hit verification temporal window. Note + * that this defines the size of the window in one direction, so + * the full time window will be <code>(2 * clusterWindow) + 1</code> + * clock-cycles in length. (i.e., it will be a length of + * <code>clusterWindow</code> before the seed hit, a length of + * <code>clusterWindow</code> after the seed hit, plus the cycle + * that includes the seed hit.) Time length is in clock-cycles. * @param clusterWindow - The number of clock-cycles around the - * hit in one direction; i.e. a value of 1 indicates that the full - * window will include the current clock-cycle, plus one cycle both - * before and after the current cycle. This gives a total number - * of cycles equal to (2 * clusterWindow) + 1. + * hit in one direction. */ public void setClusterWindow(int clusterWindow) { gtp.getCuts().setValue("clusterWindow", clusterWindow); } /** - * Sets the minimum energy needed for a seed hit to form a cluster. - * @param seedEnergyThreshold - The minimum seed energy in GeV. + * Sets the minimum seed energy needed for a hit to be considered + * for forming a cluster. This is the seed energy lower bound trigger + * cut and is in units of GeV. + * @param seedEnergyThreshold - The minimum cluster seed energy in + * GeV. */ public void setSeedEnergyThreshold(double seedEnergyThreshold) { gtp.getCuts().setValue("seedEnergyThreshold", seedEnergyThreshold); } /** - * Sets whether the clustering algorithm should use an asymmetric - * clustering window. The asymmetric window will include hits in - * a cluster that are present within the full time window ahead of - * the seed hit, but only one clock-cycle behind it. This is to - * allow for variation in hit timing with respect to the seed due - * to jitter in the hardware. + * Sets whether the behavior of the hit inclusion window with respect + * to the hit verification window. If set to <code>false</code>, + * both windows will be identical in size. Otherwise, the inclusion + * window will be equal in size after the seed hit, but encompass + * only one clock-cycle before the seed hit. * @param asymmetricWindow - <code>true</code> indicates that the * asymmetric window should be used and <code>false</code> that it * should not. */ public void setAsymmetricWindow(boolean asymmetricWindow) { - gtp.setLimitClusterRange(asymmetricWindow); + gtp.setAsymmetricWindow(asymmetricWindow); } /** * Sets whether the clustering algorithm should output diagnostic * text or not. - * @param verbose <code>true</code> indicates that the driver should + * @param verbose - <code>true</code> indicates that the driver should * output diagnostic text and <code>false</code> that it should not. */ public void setVerbose(boolean verbose) { gtp.setVerbose(verbose); } + /** + * Defines whether the output of this clusterer should be persisted + * to LCIO or not. By default, this + * @param state - <code>true</code> indicates that clusters will + * be persisted, and <code>false</code> that they will not. + */ @Override public void setWriteClusterCollection(boolean state) { // Set the flag as appropriate with the superclass. Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java Thu Aug 6 17:19:42 2015 @@ -15,37 +15,70 @@ import org.lcsim.event.base.BaseCluster; /** - * Class <code>GTPCalorimeterClusterer</code> processes events and - * converts hits into clusters, where appropriate. It uses the modified - * 2014 clustering algorithm.<br/> + * Class <code>GTPClusterer</code> is an implementation of the abstract + * class <code>AbstractClusterer</code> that is responsible for producing + * clusters using the GTP algorithm employed by the hardware.<br/> * <br/> - * For a hit to be a cluster center, it is required to have an energy - * above some tunable minimum threshold. Additionally, the hit must be - * a local maximum with respect to its neighbors and itself over a tunable - * (default 2) clock cycles. Hits that pass these checks are then required - * to additional have a total cluster energy that exceeds another tunable - * minimum threshold.<br/> + * The GTP algorithm produces clusters by finding hits representing + * local spatiotemporal energy maxima and forming a cluster from the + * hits within the aforementioned spatiotemporal window. A given hit + * is first checked to see if it exceeds some minimum energy threshold + * (referred to as the "seed energy threshold"). If this is the case, + * the algorithm looks at all hits that occurred in the same crystal as + * the comparison hit, or any crystal directly adjacent to it, within + * a programmable time window. If the hit exceeds all hits meeting these + * criteria in energy, the hit is considered the âseed hitâ of a cluster. + * Then, all hits within the 3x3 spatial window which occur in the time + * window are added to a <code>Cluster</code> object.<br/> * <br/> - * A hit is added to a cluster as a component if it has a non-zero energy - * and within the aforementioned tunable time buffer used for clustering - * and is either at the same location as the seed hit or is a neighbor - * to the seed hit. - * @author Kyle McCarty - * @author Sho Uemura + * Note that the algorithm employs two distinct temporal windows. The + * first is the âverificationâ window. This is used to check that the + * potential seed hit is a local maximum in energy, and is required to + * be symmetric (i.e. as long before the seed time as after it) to ensure + * consistency. The second temporal window is the âinclusionâ window, + * which determines which hits are included in the cluster. The inclusion + * window can be asymmetric, but can not exceed the verification window + * in length. As an example, one could choose a 12 ns verification window, + * meaning that the algorithm would 12 ns before and after the seed hit + * to check that it has the highest energy, but use a 4 ns/12 ns inclusion + * window, meaning that the algorithm would only include hits in 3x3 + * spatial window up to 4 ns before and up to 12 ns after the seed hit + * in the cluster. Due to the way the hardware processes hits, the higher + * energy parts of a cluster always occur first in time, so it is not + * necessarily desirable to include hits significantly before the seed. + * It is however, necessary to verify a hitâs status as a maximum across + * the full time window to ensure consistency in cluster formation. + * <code>GTPClusterer</code> automatically defines the inclusion window + * in terms of the verification window.<br/> + * <br/> + * <code>GTPClusterer</code> requires as input a collection of + * <code>CalorimeterHit</code> objects representing the event hits. It + * will then produce a collection of <code>Cluster</code> objects + * representing the GTP algorithm output. It is designed to be run on + * Monte Carlo events where each event represents a 2 ns beam bunch. + * If the input data is formatted in the style of hardware readout, the + * sister class <code>GTPOnlineClusterer</code> should be used instead. + * + * @author Kyle McCarty <[log in to unmask]> + * @author Sho Uemura <[log in to unmask]> + * @see Cluster + * @see CalorimeterHit + * @see AbstractClusterer + * @see GTPOnlineClusterer */ public class GTPClusterer extends AbstractClusterer { - /** * The minimum energy required for a hit to be considered as a * cluster center. Hits with energy less than this value will be - * ignored. + * ignored. This is the seed energy lower bound cut. */ private double seedEnergyThreshold; /** * Indicates the number of FADC clock cycles (each cycle is 4 ns) * before and after a given cycle that should be considered when - * checking if a cluster is a local maximum in space-time. + * checking if a cluster is a local maximum in space-time. This + * is the hit verification temporal window. */ private int clusterWindow; @@ -58,7 +91,8 @@ /** * Whether an asymmetric or symmetric window should be used for - * adding hits to a cluster. + * adding hits to a cluster. This defines the hit inclusion temporal + * window with respect to the verification window. */ private boolean limitClusterRange = false; @@ -75,213 +109,23 @@ private boolean writeHitCollection = true; /** - * Instantiates the clusterer. + * Instantiates a new instance of a Monte Carlo GTP clustering + * algorithm. It will use the default seed energy threshold of + * 50 MeV and a default hit inclusion window of +/- 2 ns. By + * default the cluster inclusion and verification windows are + * identical. */ GTPClusterer() { - super(new String[] { "seedEnergyThreshold", "clusterWindow" }, new double[] { 0.00, 2.}); - } - - /** - * Sets the clustering algorithm parameters. - */ - @Override - public void initialize() { - // Set cuts. - setSeedEnergyThreshold(getCuts().getValue("seedEnergyThreshold")); - setClusterWindow((int) getCuts().getValue("clusterWindow")); - - // Initiate the hit buffer. - hitBuffer = new LinkedList<Map<Long, CalorimeterHit>>(); - - // Populate the event buffer with (2 * clusterWindow + 1) - // empty events. These empty events represent the fact that - // the first few events will not have any events in the past - // portion of the buffer. - int bufferSize = (2 * clusterWindow) + 1; - for (int i = 0; i < bufferSize; i++) { - hitBuffer.add(new HashMap<Long, CalorimeterHit>(0)); - } - } - - /** - * Generates a list of clusters from the current hit buffer. The - * "present" event is taken to be the list of hits occurring at - * index <code>clusterWindow</code>, which is the middle of the - * buffer. - * @return Returns a <code>List</code> of <code>HPSEcalCluster - * </code> objects generated from the current event. - */ - private List<Cluster> getClusters() { - // Generate a list for storing clusters. - List<Cluster> clusters = new ArrayList<Cluster>(); - - // Get the list of hits at the current time in the event buffer. - Map<Long, CalorimeterHit> currentHits = hitBuffer.get(clusterWindow); - - // VERBOSE :: Print the cluster window. - if(verbose) { - // Print the event header. - System.out.printf("%n%nEvent:%n"); - - // Calculate some constants. - int window = (hitBuffer.size() - 1) / 2; - int bufferNum = 0; - - // Print out all of the hits in the event buffer. - for(Map<Long, CalorimeterHit> bufferMap : hitBuffer) { - System.out.printf("Buffer %d:%n", hitBuffer.size() - bufferNum - window - 1); - CalorimeterHit hit = null; - - for(Entry<Long, CalorimeterHit> entry : bufferMap.entrySet()) { - hit = entry.getValue(); - System.out.printf("\t(%3d, %3d) --> %.4f (%.4f)%n", hit.getIdentifierFieldValue("ix"), - hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy()); - } - - bufferNum++; - } - - // If there are not hits, indicate this. - if(currentHits.isEmpty()) { System.out.println("\tNo hits this event!"); } - } - - // For a hit to be a cluster center, it must be a local maximum - // both with respect to its neighbors and itself both in the - // present time and at all times within the event buffer. - seedLoop: - for (Long currentID : currentHits.keySet()) { - // Get the actual hit object. - CalorimeterHit currentHit = currentHits.get(currentID); - - // VERBOSE :: Print the current cluster. - if(verbose) { - System.out.printf("Cluster Check:%n"); - System.out.printf("\t(%3d, %3d) --> %.4f%n", currentHit.getIdentifierFieldValue("ix"), - currentHit.getIdentifierFieldValue("iy"), currentHit.getCorrectedEnergy()); - } - - // Store the energy of the current hit. - double currentEnergy = currentHit.getCorrectedEnergy(); - - // If the hit energy is lower than the minimum threshold, - // then we immediately reject this hit as a possible cluster. - if (currentEnergy < seedEnergyThreshold) { - // VERBOSE :: Note the reason the potential seed was - // rejected. - if(verbose) { System.out.printf("\tREJECT :: Does not exceed seed threshold %.4f.%n", seedEnergyThreshold); } - - // Skip to the next potential seed. - continue seedLoop; - } - - // Store the crystals that are part of this potential cluster, - // starting with the cluster seed candidate. - BaseCluster cluster = createBasicCluster(); - cluster.addHit(currentHit); - cluster.setPosition(currentHit.getDetectorElement().getGeometry().getPosition().v()); - cluster.setNeedsPropertyCalculation(false); - - // Get the set of neighbors for this hit. - Set<Long> neighbors = neighborMap.get(currentHit.getCellID()); - - // Sort through each event stored in the buffer. - int bufferIndex = 0; - for (Map<Long, CalorimeterHit> bufferHits : hitBuffer) { - // Get the hit energy at the current hit's position in - // the buffer, if it exists. Ignore the current seed candidate. - CalorimeterHit bufferHit = bufferHits.get(currentID); - if (bufferHit != null && bufferHit != currentHit) { - double bufferHitEnergy = bufferHit.getRawEnergy(); - - // Check to see if the hit at this point in the buffer - // is larger than then original hit. If it is, we may - // stop the comparison because this is not a cluster. - if (bufferHitEnergy > currentEnergy) { - // VERBOSE :: Output the reason the potential - // seed was rejected along with the - // hit that caused it. - if(verbose) { - System.out.printf("\tREJECT :: Buffer hit surpasses hit energy."); - System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", bufferHit.getIdentifierFieldValue("ix"), - bufferHit.getIdentifierFieldValue("iy"), bufferHit.getCorrectedEnergy(), bufferHit.getRawEnergy()); - } - - // Skip to the next potential seed. - continue seedLoop; - } - - // If the buffer hit is smaller, then add its energy - // to the cluster total energy. - else { - if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(bufferHit); } - else if(!limitClusterRange) { cluster.addHit(bufferHit); } - } - } - - // We must also make sure that the original hit is - // larger than all of the neighboring hits at this - // point in the buffer as well. - for (Long neighborID : neighbors) { - // Get the neighbor hit energy if it exists. - CalorimeterHit neighborHit = bufferHits.get(neighborID); - if (neighborHit != null) { - double neighborHitEnergy = neighborHit.getRawEnergy(); - - // Check to see if the neighbor hit at this point - // in the buffer is larger than then original hit. - // If it is, we may stop the comparison because this - // is not a cluster. - if (neighborHitEnergy > currentEnergy) { - // VERBOSE :: Output the reason the potential - // seed was rejected along with the - // hit that caused it. - if(verbose) { - System.out.printf("\tREJECT :: Buffer hit surpasses hit energy.%n"); - System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", neighborHit.getIdentifierFieldValue("ix"), - neighborHit.getIdentifierFieldValue("iy"), neighborHit.getCorrectedEnergy(), neighborHit.getRawEnergy()); - } - - // Skip to the next potential seed. - continue seedLoop; - } - - // If the buffer neighbor hit is smaller, then - // add its energy to the cluster total energy. - else { - if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(neighborHit); } - else if(!limitClusterRange) { cluster.addHit(neighborHit); } - } - } - } - - // Increment the buffer index. - bufferIndex++; - } - - // Add the cluster to the list of clusters. - clusters.add(cluster); - - // VERBOSE :: Output the clusters generated from this event. - if(verbose) { - System.out.printf("Cluster added.%n"); - System.out.printf("\t(%3d, %3d) --> %.4f GeV --> %d hits%n", cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"), - cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"), cluster.getEnergy(), cluster.getCalorimeterHits().size()); - for(CalorimeterHit hit : cluster.getCalorimeterHits()) { - System.out.printf("\t\tCLUSTER HIT :: (%3d, %3d) --> %.4f%n", hit.getIdentifierFieldValue("ix"), - hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy()); - } - } - } - - // Return the generated list of clusters. - return clusters; - } - - /** - * Places hits from the current event into the event hit buffer - * and processes the buffer to extract clusters. Clusters are then - * stored in the event object. - * @param event - The event to process. + super(new String[] { "seedEnergyThreshold", "clusterWindow" }, new double[] { 0.050, 2 }); + } + + /** + * Processes the argument <code>CalorimeterHit</code> collection and + * forms a collection of <code>Cluster</code> objects according to + * the GTP clustering algorithm. + * @param event - The object containing event data. + * @param hitList - A list of <code>CalorimeterHit</code> objects + * from which clusters should be formed. */ public List<Cluster> createClusters(EventHeader event, List<CalorimeterHit> hits) { // Store each hit in a set by its cell ID so that it may be @@ -327,61 +171,93 @@ } /** + * Indicates the type of cluster that is generated by this algorithm. + * @return Returns the type of cluster as a <code>ClusterType</code> + * object; specifically, returns <code>ClusterType.GTP</code>. + */ + @Override + public ClusterType getClusterType() { + return ClusterType.GTP; + } + + /** + * Sets the clustering algorithm parameters. + */ + @Override + public void initialize() { + // Set cuts. + setSeedEnergyThreshold(getCuts().getValue("seedEnergyThreshold")); + setClusterWindow((int) getCuts().getValue("clusterWindow")); + + // Initiate the hit buffer. + hitBuffer = new LinkedList<Map<Long, CalorimeterHit>>(); + + // Populate the event buffer with (2 * clusterWindow + 1) + // empty events. These empty events represent the fact that + // the first few events will not have any events in the past + // portion of the buffer. + int bufferSize = (2 * clusterWindow) + 1; + for (int i = 0; i < bufferSize; i++) { + hitBuffer.add(new HashMap<Long, CalorimeterHit>(0)); + } + } + + /** * Sets the number of clock cycles before and after a given cycle * that will be used when checking whether a given hit is a local * maximum in both time and space. Note that a value of <code>N</code> * indicates that <code>N</code> clock cycles before and * <code>N</code> clock cycles after will be considered. Thusly, a - * total of <code>2N + 1</code> clock cycles will be used. + * total of <code>2N + 1</code> clock cycles will be used. This + * defines the size of the hit verification window. The inclusion + * window is defined as a function of this, as discussed in the + * method <code>setLimitClusterRange</code>. * @param clusterWindow - The number of additional clock cycles to * include in the clustering checks. A negative value will be treated * as zero. */ void setClusterWindow(int clusterWindow) { // The cluster window of must always be at least zero. - if (clusterWindow < 0) { - this.clusterWindow = 0; - } + if (clusterWindow < 0) { this.clusterWindow = 0; } // If the cluster window is non-zero, then store it. - else { - this.clusterWindow = clusterWindow; - } - } - - /** - * Sets whether hits should be added to a cluster from the entire - * cluster window or just the "future" hits, plus one clock-cycle - * of "past" hits as a safety buffer to account for time uncertainty. + else { this.clusterWindow = clusterWindow; } + } + + /** + * Sets the behavior of the hit inclusion and verification temporal + * windows. If set to <code>true</code>, the hit inclusion window + * will be defined as one clock-cycle before the seed hit and the + * regular length of the verification window after the seed hit. If + * <code>false</code>, the inclusion window and the verification + * window are set to be identical. * @param limitClusterRange - <code>true</code> indicates that the * asymmetric clustering window should be used and <code>false</code> * that the symmetric window should be used. */ - void setLimitClusterRange(boolean limitClusterRange) { + void setAsymmetricWindow(boolean limitClusterRange) { this.limitClusterRange = limitClusterRange; } /** - * Sets the minimum energy threshold below which hits will not be - * considered as cluster centers. - * @param seedEnergyThreshold - The minimum energy for a cluster center. + * Sets the minimum energy a hit must have before it will be + * considered for cluster formation. + * @param seedThreshold - The seed threshold in GeV. */ void setSeedEnergyThreshold(double seedEnergyThreshold) { // A negative energy threshold is non-physical. All thresholds // be at least zero. - if (seedEnergyThreshold < 0.0) { - this.seedEnergyThreshold = 0.0; - } // If the energy threshold is valid, then use it. - else { - this.seedEnergyThreshold = seedEnergyThreshold; - } - } - - /** - * Sets whether diagnostic text should be written out or not. - * @param verbose - <code>true</code> indicates that diagnostic - * text will be written out and <code>false</code> that it will - * not. + if (seedEnergyThreshold < 0.0) { this.seedEnergyThreshold = 0.0; } + + // If the energy threshold is valid, then use it. + else { this.seedEnergyThreshold = seedEnergyThreshold; } + } + + /** + * Sets whether the clusterer should output diagnostic text or not. + * @param verbose - <code>true</code> indicates that the clusterer + * should output diagnostic text and <code>false</code> that it + * should not. */ void setVerbose(boolean verbose) { this.verbose = verbose; @@ -398,13 +274,177 @@ writeHitCollection = state; } - /** - * Indicates the type of cluster that is generated by this algorithm. - * @return Returns the type of cluster as a <code>ClusterType</code> - * object, specifically, <code>ClusterType.GTP</code>. - */ - @Override - public ClusterType getClusterType() { - return ClusterType.GTP; - } +/** + * Generates a list of clusters from the current hit buffer. The + * "present" event is taken to be the list of hits occurring at + * index <code>clusterWindow</code>, which is the middle of the + * buffer. + * @return Returns a <code>List</code> of <code>HPSEcalCluster + * </code> objects generated from the current event. + */ +private List<Cluster> getClusters() { + // Generate a list for storing clusters. + List<Cluster> clusters = new ArrayList<Cluster>(); + + // Get the list of hits at the current time in the event buffer. + Map<Long, CalorimeterHit> currentHits = hitBuffer.get(clusterWindow); + + // VERBOSE :: Print the cluster window. + if(verbose) { + // Print the event header. + System.out.printf("%n%nEvent:%n"); + + // Calculate some constants. + int window = (hitBuffer.size() - 1) / 2; + int bufferNum = 0; + + // Print out all of the hits in the event buffer. + for(Map<Long, CalorimeterHit> bufferMap : hitBuffer) { + System.out.printf("Buffer %d:%n", hitBuffer.size() - bufferNum - window - 1); + CalorimeterHit hit = null; + + for(Entry<Long, CalorimeterHit> entry : bufferMap.entrySet()) { + hit = entry.getValue(); + System.out.printf("\t(%3d, %3d) --> %.4f (%.4f)%n", hit.getIdentifierFieldValue("ix"), + hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy()); + } + + bufferNum++; + } + + // If there are not hits, indicate this. + if(currentHits.isEmpty()) { System.out.println("\tNo hits this event!"); } + } + + // For a hit to be a cluster center, it must be a local maximum + // both with respect to its neighbors and itself both in the + // present time and at all times within the event buffer. + seedLoop: + for (Long currentID : currentHits.keySet()) { + // Get the actual hit object. + CalorimeterHit currentHit = currentHits.get(currentID); + + // VERBOSE :: Print the current cluster. + if(verbose) { + System.out.printf("Cluster Check:%n"); + System.out.printf("\t(%3d, %3d) --> %.4f%n", currentHit.getIdentifierFieldValue("ix"), + currentHit.getIdentifierFieldValue("iy"), currentHit.getCorrectedEnergy()); + } + + // Store the energy of the current hit. + double currentEnergy = currentHit.getCorrectedEnergy(); + + // If the hit energy is lower than the minimum threshold, + // then we immediately reject this hit as a possible cluster. + if (currentEnergy < seedEnergyThreshold) { + // VERBOSE :: Note the reason the potential seed was + // rejected. + if(verbose) { System.out.printf("\tREJECT :: Does not exceed seed threshold %.4f.%n", seedEnergyThreshold); } + + // Skip to the next potential seed. + continue seedLoop; + } + + // Store the crystals that are part of this potential cluster, + // starting with the cluster seed candidate. + BaseCluster cluster = createBasicCluster(); + cluster.addHit(currentHit); + cluster.setPosition(currentHit.getDetectorElement().getGeometry().getPosition().v()); + cluster.setNeedsPropertyCalculation(false); + + // Get the set of neighbors for this hit. + Set<Long> neighbors = neighborMap.get(currentHit.getCellID()); + + // Sort through each event stored in the buffer. + int bufferIndex = 0; + for (Map<Long, CalorimeterHit> bufferHits : hitBuffer) { + // Get the hit energy at the current hit's position in + // the buffer, if it exists. Ignore the current seed candidate. + CalorimeterHit bufferHit = bufferHits.get(currentID); + if (bufferHit != null && bufferHit != currentHit) { + double bufferHitEnergy = bufferHit.getRawEnergy(); + + // Check to see if the hit at this point in the buffer + // is larger than then original hit. If it is, we may + // stop the comparison because this is not a cluster. + if (bufferHitEnergy > currentEnergy) { + // VERBOSE :: Output the reason the potential + // seed was rejected along with the + // hit that caused it. + if(verbose) { + System.out.printf("\tREJECT :: Buffer hit surpasses hit energy."); + System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", bufferHit.getIdentifierFieldValue("ix"), + bufferHit.getIdentifierFieldValue("iy"), bufferHit.getCorrectedEnergy(), bufferHit.getRawEnergy()); + } + + // Skip to the next potential seed. + continue seedLoop; + } + + // If the buffer hit is smaller, then add its energy + // to the cluster total energy. + else { + if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(bufferHit); } + else if(!limitClusterRange) { cluster.addHit(bufferHit); } + } + } + + // We must also make sure that the original hit is + // larger than all of the neighboring hits at this + // point in the buffer as well. + for (Long neighborID : neighbors) { + // Get the neighbor hit energy if it exists. + CalorimeterHit neighborHit = bufferHits.get(neighborID); + if (neighborHit != null) { + double neighborHitEnergy = neighborHit.getRawEnergy(); + + // Check to see if the neighbor hit at this point + // in the buffer is larger than then original hit. + // If it is, we may stop the comparison because this + // is not a cluster. + if (neighborHitEnergy > currentEnergy) { + // VERBOSE :: Output the reason the potential + // seed was rejected along with the + // hit that caused it. + if(verbose) { + System.out.printf("\tREJECT :: Buffer hit surpasses hit energy.%n"); + System.out.printf("\tBUFFER HIT :: (%3d, %3d) --> %.4f%n", neighborHit.getIdentifierFieldValue("ix"), + neighborHit.getIdentifierFieldValue("iy"), neighborHit.getCorrectedEnergy(), neighborHit.getRawEnergy()); + } + + // Skip to the next potential seed. + continue seedLoop; + } + + // If the buffer neighbor hit is smaller, then + // add its energy to the cluster total energy. + else { + if(limitClusterRange && bufferIndex <= clusterWindow + 1) { cluster.addHit(neighborHit); } + else if(!limitClusterRange) { cluster.addHit(neighborHit); } + } + } + } + + // Increment the buffer index. + bufferIndex++; + } + + // Add the cluster to the list of clusters. + clusters.add(cluster); + + // VERBOSE :: Output the clusters generated from this event. + if(verbose) { + System.out.printf("Cluster added.%n"); + System.out.printf("\t(%3d, %3d) --> %.4f GeV --> %d hits%n", cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"), + cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"), cluster.getEnergy(), cluster.getCalorimeterHits().size()); + for(CalorimeterHit hit : cluster.getCalorimeterHits()) { + System.out.printf("\t\tCLUSTER HIT :: (%3d, %3d) --> %.4f%n", hit.getIdentifierFieldValue("ix"), + hit.getIdentifierFieldValue("iy"), hit.getCorrectedEnergy(), hit.getRawEnergy()); + } + } + } + + // Return the generated list of clusters. + return clusters; } +} Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java Thu Aug 6 17:19:42 2015 @@ -8,18 +8,49 @@ import org.lcsim.event.EventHeader; /** - * Class <code>GTPOnlineClusterDriver</code> allows parameters for the - * readout variant of the GTP algorithm to be set. + * Class <code>GTPOnlineClusterDriver</code> is an implementation of + * the <code>ClusterDriver</code> class that defines employs the readout + * variant of the GTP hardware clustering algorithm. Specifics on the + * behavior of this algorithm can be found in its documentation.<br/> + * <br/> + * <code>GTPOnlineClusterDriver</code> allows for all of the variable + * settings used by the GTP algorithm to be defined. It also can be + * set to "verbose" mode, where it will output detailed information on + * each event and the cluster forming process. This is disabled by + * default, but can be enabled for debugging purposes.<br/> + * <br/> + * Lastly, <code>GTPOnlineClusterDriver</code> can be set to draw its + * settings from the <code>ConfigurationManager</code> static class, + * which reads and stores settings extracted directly from EvIO data. + * This option is disabled by default, and can be activated with the + * method <code>setUseDAQConfig</code>. When enabled, no clusters will + * be generated until <code>ConfigurationManager</code> reads a config + * event. This requires that the driver <code>DAQConfigDriver</code> + * be included in the driver chain.<br/> + * <br/> + * <code>GTPOnlineClusterDriver</code> is designed for use on hardware + * readout data or Monte Carlo formatted in this style. It can not be + * used for 2-ns beam bunch formatted data. <code>GTPClusterDriver</code> + * should be used for this data instead. * * @author Kyle McCarty <[log in to unmask]> + * @see GTPOnlineClusterer + * @see ConfigurationManager + * @see org.hps.recon.ecal.daqconfig.DAQConfigDriver */ public class GTPOnlineClusterDriver extends ClusterDriver { + /** An instance of the clustering algorithm object for producing + * cluster objects. */ private final GTPOnlineClusterer gtp; + /** Indicates whether the <code>ConfigurationManager</code> object + * should be used for clustering settings or not. */ private boolean useDAQConfig = false; /** - * Instantiates a new clustering algorithm using the readout - * variant of the GTP clustering algorithm. + * Initializes a clustering driver. This implements the readout + * variant of the hardware GTP algorithm, as defined in the class + * <code>GTPClusterer</code>. + * @see GTPOnlineClusterer */ public GTPOnlineClusterDriver() { // Instantiate the clusterer. @@ -48,6 +79,15 @@ }); } + /** + * Processes an an <code>EventHeader</code> object to generate + * clusters. Events will not be processed if <code>UseDAQConfig</code> + * is <code>true</code> unless the <code>ConfigurationManager</code> + * static class has received a DAQ configuration from the event + * stream and is initialized. Driver <code>DAQConfigDriver</code> + * must be in the driver chain for this to occur. + * @see org.hps.recon.ecal.daqconfig.DAQConfigDriver + */ @Override public void process(EventHeader event) { // Only process an event if either the DAQ configuration is not @@ -58,7 +98,8 @@ } /** - * Outputs the clusterer settings. + * Outputs the clusterer settings at driver initialization, assuming + * <code>setVerbose</code> is set to <code>true</code>. */ @Override public void startOfData() { @@ -68,7 +109,8 @@ /** * Sets the minimum seed energy needed for a hit to be considered - * for forming a cluster. + * for forming a cluster. This is the seed energy lower bound trigger + * cut and is in units of GeV. * @param seedEnergyThreshold - The minimum cluster seed energy in * GeV. */ @@ -80,6 +122,9 @@ /** * Sets the number of clock-cycles to include in the clustering * window before the seed hit. One clock-cycle is four nanoseconds. + * This defines the first half of the temporal hit inclusion window. + * The temporal hit verification window is defined as + * <code>max(windowAfter, windowBefore) * 2) + 1</code>. * @param cyclesBefore - The length of the clustering window before * the seed hit in clock cycles. */ @@ -90,8 +135,12 @@ /** * Sets the number of clock-cycles to include in the clustering * window after the seed hit. One clock-cycle is four nanoseconds. + * This defines the latter half of the temporal hit inclusion window. + * The temporal hit verification window is defined as + * <code>max(windowAfter, windowBefore) * 2) + 1</code>. * @param cyclesAfter - The length of the clustering window after * the seed hit in clock cycles. + * @see GTPOnlineClusterer */ public void setWindowAfter(int cyclesAfter) { gtp.setWindowAfter(cyclesAfter); @@ -109,9 +158,14 @@ /** * Sets whether GTP settings should be drawn from the EvIO data - * DAQ configuration or read from the steering file. + * DAQ configuration or read from the steering file. If this is + * set to <code>true</code>, no clusters will be generated until + * the static class <code>ConfigurationManager</code> has received + * a DAQ settings event and initialized. If this class is not part + * of the driver chain, then no clusters will ever be created. * @param state - <code>true</code> means that DAQ configuration * will be used and <code>false</code> that it will not. + * @see org.hps.recon.ecal.daqconfig.DAQConfigDriver */ public void setUseDAQConfig(boolean state) { useDAQConfig = state; Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java Thu Aug 6 17:19:42 2015 @@ -16,74 +16,115 @@ /** * Class <code>GTPOnlineClusterer</code> is an implementation of the - * GTP clustering algorithm for EVIO readout data for use in either - * online reconstruction/diagnostics or for general analysis of EVIO - * readout data.<br/> + * abstract class <code>AbstractClusterer</code> that is responsible + * for producing clusters using the GTP algorithm employed by the + * hardware.<br/> * <br/> - * The GTP algorithm searches the set of hits in a readout event and - * compares them to select those that are a maximum in their 3x3 window - * and across a period of time that can be set. Hits that are maxima - * are declared "cluster seeds" and a cluster is created from them. - * All hits within the clustering window of the seed time are then - * added to the cluster and it is written to the event stream.<br/> + * The GTP algorithm produces clusters by finding hits representing + * local spatiotemporal energy maxima and forming a cluster from the + * hits within the aforementioned spatiotemporal window. A given hit + * is first checked to see if it exceeds some minimum energy threshold + * (referred to as the "seed energy threshold"). If this is the case, + * the algorithm looks at all hits that occurred in the same crystal as + * the comparison hit, or any crystal directly adjacent to it, within + * a programmable time window. If the hit exceeds all hits meeting these + * criteria in energy, the hit is considered the âseed hitâ of a cluster. + * Then, all hits within the 3x3 spatial window which occur in the time + * window are added to a <code>Cluster</code> object.<br/> * <br/> - * The GTP algorithm uses three time windows. THe verification window - * is the time around the seed hit in which it is required to have more - * energy than any other hits in the 3x3 spatial window surrounding it. - * This is always symmetric. The other two windows combined define the - * clustering window. The clustering window is composed of a window - * before and a window after the seed time. These may be defined using - * different values. The window after should be as long or longer than - * the window before to make physical sense. The verification window is - * then defined as the larger of the two constituents of the clustering - * window. This is required for clustering to be consistent. + * Note that the algorithm employs two distinct temporal windows. The + * first is the âverificationâ window. This is used to check that the + * potential seed hit is a local maximum in energy, and is required to + * be symmetric (i.e. as long before the seed time as after it) to ensure + * consistency. The second temporal window is the âinclusionâ window, + * which determines which hits are included in the cluster. The inclusion + * window can be asymmetric, but can not exceed the verification window + * in length. As an example, one could choose a 12 ns verification window, + * meaning that the algorithm would 12 ns before and after the seed hit + * to check that it has the highest energy, but use a 4 ns/12 ns inclusion + * window, meaning that the algorithm would only include hits in 3x3 + * spatial window up to 4 ns before and up to 12 ns after the seed hit + * in the cluster. Due to the way the hardware processes hits, the higher + * energy parts of a cluster always occur first in time, so it is not + * necessarily desirable to include hits significantly before the seed. + * It is however, necessary to verify a hitâs status as a maximum across + * the full time window to ensure consistency in cluster formation. + * <code>GTPOnlineClusterer</code> automatically selects the larger of + * the two inclusion window parts as the verification window length.<br/> + * <br/> + * <code>GTPOnlineClusterer</code> requires as input a collection of + * <code>CalorimeterHit</code> objects representing the event hits. It + * will then produce a collection of <code>Cluster</code> objects + * representing the GTP algorithm output. It also produces a series of + * distribution plots under the âGTP(O) Cluster Plotsâ header. It is + * designed to be run on readout events, either from the hardware or + * Monte Carlo that has been processed through the readout simulation. + * If the input data is formatted into constant-time beam bunches, the + * sister class <code>GTPClusterer</code> should be used instead. * * @author Kyle McCarty <[log in to unmask]> + * @see Cluster + * @see CalorimeterHit + * @see AbstractClusterer + * @see GTPClusterer */ public class GTPOnlineClusterer extends AbstractClusterer { - - // The size of the temporal window in nanoseconds. By default, - // this is 1 clock-cycle before and 3 clock-cycles after. + /** + * The length of the temporal window for inclusing clusters that + * occur before the seed hit. + */ private double timeBefore = 4; + + /** + * The length of the temporal window for including clusters that + * occur after the seed hit. + */ private double timeAfter = 12; + + /** + * The length of the temporal window for verifying that a hit is + * a local maximum in energy. This length represents both halves + * of the verification window, so the full length would be defined + * by <code>timeWindow * 2 + 4</code> ns. + */ private double timeWindow = 12; - - // Cluster formation energy thresholds. Currently, the hardware - // only supports a lower bound seed energy. Units are in GeV. + + /** + * The minimum energy a hit must have to be considered for cluster + * seed formation. Units are in GeV. + */ private double seedThreshold = 0.050; - // Internal variables. + /** + * Controls whether or not verbose diagnostic information is output. + */ private boolean verbose = false; // Diagnostic plots. private AIDA aida = AIDA.defaultInstance(); - IHistogram1D hitEnergy = aida.histogram1D("GTP(O) Cluster Plots :: Hit Energy Distribution", 256, -1.0, 2.2); - IHistogram1D clusterSeedEnergy = aida.histogram1D("GTP(O) Cluster Plots :: Cluster Seed Energy Distribution", 176, 0.0, 2.2); - IHistogram1D clusterHitCount = aida.histogram1D("GTP(O) Cluster Plots :: Cluster Hit Count Distribution", 9, 1, 10); - IHistogram1D clusterTotalEnergy = aida.histogram1D("GTP(O) Cluster Plots :: Cluster Total Energy Distribution", 176, 0.0, 2.2); - IHistogram2D hitDistribution = aida.histogram2D("GTP(O) Cluster Plots :: Hit Distribution", 46, -23, 23, 11, -5.5, 5.5); - IHistogram2D clusterDistribution = aida.histogram2D("GTP(O) Cluster Plots :: Cluster Seed Distribution", 46, -23, 23, 11, -5.5, 5.5); - IHistogram1D energyDistribution = aida.histogram1D("GTP(O) Cluster Plots :: Percent Negative Energy Distribution", 100, 0.0, 1.0); + private IHistogram1D hitEnergy = aida.histogram1D("GTP(O) Cluster Plot/Hit Energy Distribution", 256, -1.0, 2.2); + private IHistogram1D clusterSeedEnergy = aida.histogram1D("GTP(O) Cluster Plots/Cluster Seed Energy Distribution", 176, 0.0, 2.2); + private IHistogram1D clusterHitCount = aida.histogram1D("GTP(O) Cluster Plots/Cluster Hit Count Distribution", 9, 1, 10); + private IHistogram1D clusterTotalEnergy = aida.histogram1D("GTP(O) Cluster Plots/Cluster Total Energy Distribution", 176, 0.0, 2.2); + private IHistogram2D hitDistribution = aida.histogram2D("GTP(O) Cluster Plots/Hit Distribution", 46, -23, 23, 11, -5.5, 5.5); + private IHistogram2D clusterDistribution = aida.histogram2D("GTP(O) Cluster Plots/Cluster Seed Distribution", 46, -23, 23, 11, -5.5, 5.5); + private IHistogram1D energyDistribution = aida.histogram1D("GTP(O) Cluster Plots/Percent Negative Energy Distribution", 100, 0.0, 1.0); /** * Instantiates a new instance of a readout GTP clustering algorithm. + * This will use the default seed energy threshold of 50 MeV. */ GTPOnlineClusterer() { super(new String[] { "seedThreshold" }, new double[] { 0.050 }); } /** - * Gets any relevant cuts from the superclass and sets the local - * clusterer variables accordingly. - */ - public void initialize() { - seedThreshold = getCuts().getValue("seedThreshold"); - } - - /** - * Reads in hits and processes them into clusters as per the GTP - * clustering algorithm implemented in the hardware. + * Processes the argument <code>CalorimeterHit</code> collection and + * forms a collection of <code>Cluster</code> objects according to + * the GTP clustering algorithm. * @param event - The object containing event data. + * @param hitList - A list of <code>CalorimeterHit</code> objects + * from which clusters should be formed. */ @Override public List<Cluster> createClusters(EventHeader event, List<CalorimeterHit> hitList) { @@ -95,6 +136,7 @@ System.out.println("=== GTP Readout Clusterer ============================================"); System.out.println("======================================================================"); + // Sort the hits by x-index and then by y-index. Collections.sort(hitList, new Comparator<CalorimeterHit>() { @Override public int compare(CalorimeterHit firstHit, CalorimeterHit secondHit) { @@ -106,6 +148,8 @@ } } }); + + // Print the hit collection. System.out.println("Event Hit Collection:"); for(CalorimeterHit hit : hitList) { int ix = hit.getIdentifierFieldValue("ix"); @@ -155,7 +199,7 @@ protoCluster.setPosition(seed.getDetectorElement().getGeometry().getPosition().v()); protoCluster.setNeedsPropertyCalculation(false); - // Iterate over the other hits and if the are within + // Iterate over the other hits and if they are within // the clustering spatiotemporal window, compare their // energies. hitLoop: @@ -217,16 +261,18 @@ // VERBOSE :: Print out all the clusters in the event. if(verbose) { + // Print the clusters. System.out.println("Event Cluster Collection:"); for(Cluster cluster : clusterList) { + // Output basic cluster positional and energy data. CalorimeterHit seedHit = cluster.getCalorimeterHits().get(0); int ix = seedHit.getIdentifierFieldValue("ix"); int iy = seedHit.getIdentifierFieldValue("iy"); double energy = cluster.getEnergy(); double time = seedHit.getTime(); - System.out.printf("\tCluster --> %6.3f GeV at (%3d, %3d) and at t = %.2f%n", energy, ix, iy, time); + // Output the cluster hit collection. for(CalorimeterHit hit : cluster.getCalorimeterHits()) { int hix = hit.getIdentifierFieldValue("ix"); int hiy = hit.getIdentifierFieldValue("iy"); @@ -241,16 +287,125 @@ // VERBOSE :: Print a new line. if(verbose) { System.out.println(); } + // Return the list of clusters. return clusterList; } /** - * Checks whether the hit <code>hit</code> keeps the hit <code>seed - * </code> from meeting the criteria for being a seed hit. Note that - * this does not check to see if the two hits are within the valid - * spatiotemporal window of one another. + * Gets the type of cluster produced by this clusterer. + * @return Returns the cluster type as a <code>ClusterType</code> + * enumerable. + */ + @Override + public ClusterType getClusterType() { + return ClusterType.GTP_ONLINE; + } + + /** + * Gets the seed energy lower bound threshold in units of GeV. + * @return Returns the threshold as a <code>double</code>. + */ + public double getSeedLowThreshold() { return seedThreshold; } + + /** + * Gets the number of nanoseconds before the seed hit time that + * the clusterer will look to include hits when a cluster is formed. + * @return Returns the time window as a <code>double</code>. + */ + public double getWindowBefore() { return timeBefore; } + + /** + * Gets the number of nanoseconds after the seed hit time that + * the clusterer will look to include hits when a cluster is formed. + * @return Returns the time window as a <code>double</code>. + */ + public double getWindowAfter() { return timeAfter; } + + /** + * Sets up the clusterer parameters so that it is ready to be used. + * This should be run before the cluster formation. + */ + @Override + public void initialize() { + seedThreshold = getCuts().getValue("seedThreshold"); + } + + /** + * Returns whether the clusterer will output verbose diagnostic + * information. + * @return Returns <code>true</code> if the clusterer will output + * diagnostic information and <code>false</code> otherwise. + */ + boolean isVerbose() { return verbose; } + + /** + * Sets the minimum energy a hit must have before it will be + * considered for cluster formation. + * @param seedThreshold - The seed threshold in GeV. + */ + void setSeedLowThreshold(double seedThreshold) { + this.seedThreshold = seedThreshold; + } + + /** + * Sets whether the clusterer should output diagnostic text or not. + * @param verbose - <code>true</code> indicates that the clusterer + * should output diagnostic text and <code>false</code> that it + * should not. + */ + void setVerbose(boolean verbose) { + this.verbose = verbose; + } + + /** + * Sets the number of clock-cycles to include in the clustering + * window before the seed hit. One clock-cycle is four nanoseconds. + * Note that the larger of this time and the time defined in method + * <code>setWindowAfter</code> will be the verification window size. + * @param cyclesBefore - The length of the clustering window before + * the seed hit in clock cycles. + */ + void setWindowBefore(int cyclesBefore) { + // The cluster window can not be negative. + if(cyclesBefore < 0) { cyclesBefore = 0; } + + // Convert the window to nanoseconds and set the two time + // windows appropriately. + timeBefore = cyclesBefore * 4; + timeWindow = Math.max(timeBefore, timeAfter); + } + + /** + * Sets the number of clock-cycles to include in the clustering + * window after the seed hit. One clock-cycle is four nanoseconds. + * Note that the larger of this time and the time defined in method + * <code>setWindowBefore</code> will be the verification window size. + * @param cyclesAfter - The length of the clustering window after + * the seed hit in clock cycles. + */ + void setWindowAfter(int cyclesAfter) { + // The cluster window can not be negative. + if(cyclesAfter < 0) { cyclesAfter = 0; } + + // Convert the window to nanoseconds and set the two time + // windows appropriately. + timeAfter = cyclesAfter * 4; + timeWindow = Math.max(timeBefore, timeAfter); + } + + /** + * Compares the argument <code>CalorimeterHit</code> <code>hit</code> + * against the <code>CalorimeterHit</code> <code>seed</code> to see + * if <code>seed</code> meets the criteria for a seed hit given the + * presence of <code>hit</code>, which is assumed to be located in + * the appropriate spatiotemporal window.<br/> + * <br/> + * Note that it is the responsibility of the calling method to + * ascertain whether the two <code>CalorimeterHit</code> objects + * are actually within the proper spatial and temporal windows of + * one another. * @param seed - The potential seed hit. - * @param hit - The hit to compare with the seed. + * @param hit - The hit with which to compare the seed. * @return Returns <code>true</code> if either the two hits are the * same hit or if the hit does not invalidate the potential seed. * Returns <code>false</code> otherwise. @@ -303,10 +458,12 @@ } /** - * Checks whether the hit <code>hit</code> falls within the spatial - * window of the hit <code>Seed</code>. This is defined as within - * 1 index of the seed's x-index and similarly for the seed's - * y-index. + * Checks whether the <code>CalorimeterHit</code> <code>hit</code> + * is within the 3x3 spatial window of <code>CalorimeterHit</code> + * <code>seed</code>. This is defined as <code>seed</code> having + * an x-index within +/-1 of the x-index of <code>hit</code> and + * similarly for the y-index. Allowance is made for the fact that + * the x-indices go from -1 to 1 and skip zero. * @param seed - The seed hit. * @param hit - The comparison hit. * @return Returns <code>true</code> if either both hits are the @@ -353,9 +510,9 @@ } /** - * Checks whether the hit <code>hit</code> is within the temporal - * window of the hit <code>seed</code> for the purpose of seed - * verification. + * Checks whether <code>CalorimeterHit</code> <code>hit</code> is + * within the verification temporal window for potential seed hit + * <code>seed</code>. * @param seed - The seed hit. * @param hit - The comparison hit. * @return Returns <code>true</code> if the comparison hit is within @@ -373,9 +530,9 @@ } /** - * Checks whether the hit <code>hit</code> is within the temporal - * window of the hit <code>seed</code> for the purpose of adding - * a hit to a cluster. + * Checks whether <code>CalorimeterHit</code> <code>hit</code> is + * within the inclusion temporal window for potential seed hit + * <code>seed</code>. * @param seed - The seed hit. * @param hit - The comparison hit. * @return Returns <code>true</code> if the comparison hit is within @@ -397,87 +554,11 @@ return (hitTime - seedTime) <= timeAfter; } - // If the times are the same, the are within the window. + // If the times are the same, they are within the window. if(hitTime == seedTime) { return true; } // Otherwise, one or both times is undefined and should not be // treated as within time. else { return false; } } - - /** - * Gets the seed energy lower bound threshold in units of GeV. - * @return Returns the seed energy lower bound threshold. - */ - public double getSeedLowThreshold() { return seedThreshold; } - - /** - * Gets the number of nanoseconds before the seed hit time the - * clusterer will look to verify the seed hit. - * @return Returns the size of the time window before the seed - * hit time. - */ - public double getWindowBefore() { return timeBefore; } - - /** - * Gets the number of nanoseconds after the seed hit time the - * clusterer will look to verify the seed hit. - * @return Returns the size of the time window after the seed - * hit time. - */ - public double getWindowAfter() { return timeAfter; } - - /** - * Returns whether the clusterer will output verbose diagnostic - * information. - * @return Returns <code>true</code> if the clusterer will output - * diagnostic information and <code>false</code> otherwise. - */ - public boolean isVerbose() { return verbose; } - - /** - * Sets the minimum energy a hit must have before it will be - * considered for cluster formation. - * @param seedThreshold - The seed threshold in GeV. - */ - public void setSeedLowThreshold(double seedThreshold) { - this.seedThreshold = seedThreshold; - } - - /** - * Sets the number of clock-cycles to include in the clustering - * window before the seed hit. One clock-cycle is four nanoseconds. - * @param cyclesBefore - The length of the clustering window before - * the seed hit in clock cycles. - */ - public void setWindowBefore(int cyclesBefore) { - timeBefore = cyclesBefore * 4; - timeWindow = Math.max(timeBefore, timeAfter); - } - - /** - * Sets the number of clock-cycles to include in the clustering - * window after the seed hit. One clock-cycle is four nanoseconds. - * @param cyclesAfter - The length of the clustering window after - * the seed hit in clock cycles. - */ - public void setWindowAfter(int cyclesAfter) { - timeAfter = cyclesAfter * 4; - timeWindow = Math.max(timeBefore, timeAfter); - } - - /** - * Sets whether the clusterer should output diagnostic text or not. - * @param verbose - <code>true</code> indicates that the clusterer - * should output diagnostic text and <code>false</code> that it - * should not. - */ - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - @Override - public ClusterType getClusterType() { - return ClusterType.GTP_ONLINE; - } } Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ConfigurationManager.java Thu Aug 6 17:19:42 2015 @@ -10,7 +10,7 @@ * the DAQ configuration that can be parsed from EVIO files. It works * in conjunction with the <code>DAQConfigDriver</code>, which obtains * the configuration parser object when available and passes it to this - * manager, and <code>TriggerConfig</code>, which parses the EVIO data. + * manager, and <code>EvioDAQParser</code>, which parses the EVIO data. * * @author Kyle McCarty <[log in to unmask]> * @see DAQConfigDriver Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/DAQConfigDriver.java Thu Aug 6 17:19:42 2015 @@ -5,8 +5,25 @@ import org.lcsim.event.EventHeader; import org.lcsim.util.Driver; +/** + * Class <code>DAQConfigDriver</code> is responsible for checking events + * for DAQ configuration settings, and then passing them to the associated + * class <code>ConfigurationManager</code> so that they can be accessed + * by other classes.<br/> + * <br/> + * This driver must be included in the driver chain if any other drivers + * in the chain rely on <code>ConfigurationManager</code>, as it can + * not be initialized otherwise. + * + * @author Kyle McCarty + * @see ConfigurationManager + */ public class DAQConfigDriver extends Driver { - + /** + * Checks an event for the DAQ configuration banks and passes them + * to the <code>ConfigurationManager</code>. + * @param - The event to check. + */ @Override public void process(EventHeader event) { // Check if a trigger configuration bank exists. @@ -21,5 +38,4 @@ ConfigurationManager.updateConfiguration(daqConfig); } } - } Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/EvioDAQParser.java Thu Aug 6 17:19:42 2015 @@ -12,6 +12,18 @@ import org.hps.conditions.ecal.EcalChannel; import org.hps.conditions.ecal.EcalConditions; +/** + * Class <code>EvioDAQParser</code> takes DAQ configuration banks from + * EvIO data and extracts the configuration parameters from them. These + * are then stored within package-accessible variables within the class. + * <br/><br/> + * Note that this class should not be used directly to acquire DAQ + * configuration data. It is intended to be used internally by the EvIO + * parser and the class <code>ConfigurationManager</code>. The latter + * should be used for accessing this information for any other classes. + * + * @author Nathan Baltzell <[log in to unmask]> + */ public class EvioDAQParser { /* * Read/Parse/Save the DAQ trigger configuration settings. @@ -22,135 +34,271 @@ * * GTP settings and Prescale factors will need to be added to this class when added to EVIO. * - * TODO: Error in EVIO format for Crate 39 for 2014 data requires another JEVIO workaround (realized Feb 16). + * TODO: Error in EVIO format for Crate 39 for 2014 data requires another JEVIO workaround (realized Feb. 16). * ** This was fixed in EVIO for data after run 4044. * * TODO: Manually put in GTP settings based on run number for 2014 data. * TODO: Manually deal with change in format of SSP_HPS_SINGLES_NMIN (at 3312(?)). * - * TODO: Restructure, clean up.. - * - * @author <[log in to unmask]> - */ - public int nBanks = 0; + * TODO: Restructure, clean up... + */ + /** The EvIO bank identification tag for DAQ configuration banks. */ public static final int BANK_TAG = 0xE10E; - // need to know these in order to interpret DAQ strings: + // Stores the hardware codes for each trigger type. private static final int[] singlesIOsrc = { 20, 21 }; private static final int[] pairsIOsrc = { 22, 23 }; // Dump everything read from the DAQ Configuration Bank, minimal interpretation: - Map<String,List<String>> configMap = new HashMap<String,List<String>>(); - - // link ECAL FADC channel settings to EcalChannels: - Map<EcalChannel,Float> GAIN = new HashMap<EcalChannel,Float>(); - Map<EcalChannel,Float> PEDESTAL = new HashMap<EcalChannel,Float>(); - Map<EcalChannel,Integer> THRESHOLD = new HashMap<EcalChannel,Integer>(); - - // private boolean debug = true; + private Map<String, List<String>> configMap = new HashMap<String, List<String>>(); + + // Class parameters. + private int nBanks = 0; private boolean debug = false; // FADC Config: + /** The length of time after a pulse-crossing event that the pulse + * should be integrated. Uses units of clock-cycles. */ int fadcNSA = 0; + /** The length of time before a pulse-crossing event that the pulse + * should be integrated. Uses units of clock-cycles. */ int fadcNSB = 0; + /** The maximum number of pulses that will be extracted from a single + * channel within a readout window. */ int fadcNPEAK = 0; + /** The pulse-processing mode used by the FADC. This should be 1, + * 3, or 7. */ int fadcMODE = 0; + /** The size of readout window in nanoseconds. */ int fadcWIDTH = 0; + /** The time-offset of the readout window in ns. */ int fadcOFFSET = 0; + /** Map of <code>EcalChannel</code> to the gain for that channel. + * Uses units of ADC / MeV for the mapped value. */ + Map<EcalChannel, Float> GAIN = new HashMap<EcalChannel, Float>(); + /** Map of <code>EcalChannel</code> to the pedestal for that channel. + * Uses units of ADC for the mapped value. */ + Map<EcalChannel, Float> PEDESTAL = new HashMap<EcalChannel, Float>(); + /** Map of <code>EcalChannel</code> to the threshold for that channel. + * Uses units of ADC for the mapped value. */ + Map<EcalChannel, Integer> THRESHOLD = new HashMap<EcalChannel, Integer>(); // GTP Clustering Cut Values: + /** The seed energy lower bound cut used by the clusterer. Value is + * in units of MeV. */ int gtpMinSeedEnergy = 0; + /** The length of the clustering verification/inclusion window before + * the seed hit. Uses units of clock-cycles. */ int gtpWindowBefore = 0; + /** The length of the clustering verification/inclusion window after + * the seed hit. Uses units of clock-cycles. */ int gtpWindowAfter = 0; // Triggers Enabled: + /** Indicates whether the singles triggers are enabled or not. Uses + * the format <code>{ Singles0_Enabled, Singles1_Enabled }</code>. */ boolean[] singlesEn = { false, false }; + /** Indicates whether the pair triggers are enabled or not. Uses + * the format <code>{ Pair0_Enabled, Pair1_Enabled }</code>. */ boolean[] pairsEn = { false, false }; // Singles Cuts Enabled: + /** Indicates whether the singles trigger cluster hit count cuts + * are enabled or not. Uses the format + * <code>{ Singles0_Cut_Enabled, Singles1_Cut_Enabled }</code>. */ boolean[] singlesNhitsEn = { false, false }; + /** Indicates whether the singles trigger cluster total energy lower + * bound cuts are enabled or not. Uses the format + * <code>{ Singles0_Cut_Enabled, Singles1_Cut_Enabled }</code>. */ boolean[] singlesEnergyMinEn = { false, false }; + /** Indicates whether the singles trigger cluster total energy upper + * bound cuts are enabled or not. Uses the format + * <code>{ Singles0_Cut_Enabled, Singles1_Cut_Enabled }</code>. */ boolean[] singlesEnergyMaxEn = { false, false }; // Pairs Cuts Enabled: + /** Indicates whether the pair trigger pair energy sum cuts are + * enabled or not. Uses the format + * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */ boolean[] pairsEnergySumMaxMinEn = { false, false }; + /** Indicates whether the pair trigger pair energy difference cuts + * are enabled or not. Uses the format + * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */ boolean[] pairsEnergyDiffEn = { false, false }; + /** Indicates whether the pair trigger pair coplanarity cuts are + * enabled or not. Uses the format + * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */ boolean[] pairsCoplanarityEn = { false, false }; + /** Indicates whether the pair trigger pair energy slope cuts are + * enabled or not. Uses the format + * <code>{ Pair0_Cut_Enabled, Pair1_Cut_Enabled }</code>. */ boolean[] pairsEnergyDistEn = { false, false }; // Singles Cut Values: + /** Specifies the value of the singles trigger cluster hit count + * cuts. Use the format, in units of hits, + * <code>{ Singles0_Cut_Value, Singles1_Cut_Value }</code>. */ int[] singlesNhits = { 0, 0 }; + /** Specifies the value of the singles trigger cluster total energy + * lower bound cuts. Use the format, in units of MeV, + * <code>{ Singles0_Cut_Value, Singles1_Cut_Value }</code>. */ int[] singlesEnergyMin = { 0, 0 }; + /** Specifies the value of the singles trigger cluster total energy + * upper bound cuts. Use the format, in units of MeV, + * <code>{ Singles0_Cut_Value, Singles1_Cut_Value }</code>. */ int[] singlesEnergyMax = { 0, 0 }; // Pairs Cut Values: + /** Specifies the value of the pair trigger cluster hit count cuts. + * Use the format, in units of hits, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsNhitsMin = { 0, 0 }; + /** Specifies the value of the pair trigger cluster total energy + * lower bound cuts. Use the format, in units of MeV, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsEnergyMin = { 0, 0 }; + /** Specifies the value of the pair trigger cluster total energy + * upper bound cuts. Use the format, in units of MeV, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsEnergyMax = { 0, 0 }; + /** Specifies the value of the pair trigger pair energy sum upper + * bound cuts. Use the format, in units of MeV, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsEnergySumMin = { 0, 0 }; + /** Specifies the value of the pair trigger pair energy sum lower + * bound cuts. Use the format, in units of MeV, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsEnergySumMax = { 0, 0 }; + /** Specifies the value of the pair trigger pair energy difference + * cuts. Use the format, in units of MeV, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsEnergyDiffMax = { 0, 0 }; + /** Specifies the value of the pair trigger pair coplanarity cuts. + * Use the format, in units of degrees, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsCoplanarityMax = { 0, 0 }; + /** Specifies the value of the pair trigger pair time coincidence + * cuts. Use the format, in units of nanoseconds, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsTimeDiffMax = { 0, 0 }; + /** Specifies the value of the pair trigger pair energy slope cuts. + * Use the format, in units of MeV, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ int[] pairsEnergyDistMin = { 0, 0 }; // Pairs Cut Parameters: + /** Specifies the value of the pair trigger pair energy slope cuts' + * parameter F. Use the format, in units of MeV / mm, + * <code>{ Pair0_Cut_Value, Pair1_Cut_Value }</code>. */ float[] pairsEnergyDistSlope = { 0, 0 }; - // Have to remember the previous slot line in order to interpret the data: + // Tracks the last FADC slot seen. This is needed for parsing FADC + // threshold, pedestal, and gain information. private int thisFadcSlot = 0; // Cache local set of EcalChannels: private EcalConditions ecalConditions = null; private List<EcalChannel> channels = new ArrayList<EcalChannel>(); + /** + * Instantiates the <code>EvioDAQParser</code>. + */ public EvioDAQParser() { + // Create a map to map crystals to their database channel object. ecalConditions = DatabaseConditionsManager.getInstance().getEcalConditions(); for (int ii = 0; ii < 442; ii++) { - channels.add(findChannel(ii+1)); + channels.add(findChannel(ii + 1)); } } - public void parse(int crate, int runNumber, String[] dump) { + /** + * Parses a set of configuration tables to obtain DAQ configuration + * parameters. + * @param crate - The crate associated with the configuration tables. + * @param runNumber - The run number for the current data set. + * @param configurationTables - Tables containing DAQ configuration + * parameters. + */ + public void parse(int crate, int runNumber, String[] configurationTables) { + // Track the number of banks that have been parsed. If the + // parameter values have not been populated after a certain + // number of banks, there is missing information. nBanks++; - loadConfigMap(crate,dump); - if (debug) printMap(); + + // Create a map that maps an identifier for each configuration + // parameter (its parameter key) to any values associated + // with it (its parameter values). + loadConfigMap(crate, configurationTables); + + // If debugging text is enabled, print the map to the terminal. + if(debug) { printMap(); } + + // If this run is known to be missing configuration values, + // handle the missing values. fixConfigMap2014Run(runNumber); + + // Parse the previously generated configuration map and extract + // the DAQ configuration from it. parseConfigMap(); + // If the expected number of banks have been parsed and debugging + // text is enabled, print out all of the parsed variables. if(nBanks > 2 && debug) { printVars(); } } - /* - * The first parsing routine. Just dumps the config strings - * into a map whose keys are the first column in the config file. - * Also treats some special cases. - */ - private void loadConfigMap(int crate, String[] dump) { - for(String dump1 : dump) { - for(String line : dump1.trim().split("\n")) { + /** + * Converts the textual configuration information into a map, where + * the first column value becomes the map entry key and the remainder + * becomes the map entry value. + * @param crate - The calorimeter crate associated with the textual + * configuration data. + * @param configTables - An array of textual configuration tables that + * contain the DAQ configuration parameters. + */ + private void loadConfigMap(int crate, String[] configTables) { + // Iterate over each configuration table. + for(String configTable : configTables) { + // Split each table into rows and iterate over the rows. + rowLoop: + for(String line : configTable.trim().split("\n")) { + // Split the first column from the row. + String[] cols = line.trim().split(" +", 2); - String[] cols = line.trim().split(" +", 2); - if(cols.length < 2) continue; + // If there are fewer than two segments after the split, + // then this is not a valid parameter entry. + if(cols.length < 2) continue rowLoop; + // The row name is the value of the first column. The + // rest are typically values. String key = cols[0]; - List<String> vals = new ArrayList<String> - (Arrays.asList(cols[1].trim().split(" +"))); + List<String> vals = new ArrayList<String>(Arrays.asList(cols[1].trim().split(" +"))); + // If no values are present, this is not a valid entry. if (vals.size() < 1) { - continue; + continue rowLoop; } - - // SPECIAL CASE: - // parse the 16+1 column slot configurations. + + // SPECIAL CASE:: Key "FADC250" + // This entry marks parameter values for FADC channels, + // such as pedestals, gains, and thresholds. These are + // stored in separate lists from the other parameters. if (key.startsWith("FADC250")) { parseFADC(crate, key.trim(), vals); } - // SPECIAL CASE: - // figure out which triggers are enabled: + // SPECIAL CASE: Key "SSP_HPS_SET_IO_SRC" + // This entry indicates which triggers are enabled and + // needs to be parsed differently than normal. else if(key.startsWith("SSP_HPS_SET_IO_SRC")) { + // The first "parameter value" is a hardware code + // that identifies the trigger. Obtain it. int trig = Integer.valueOf(vals.get(1)); + + // There are two trigger of each type, singles and + // pairs. Compare the hardware code to the codes + // for each of these triggers to determine which + // it this parameter entry represents and then set + // its value appropriately. for (int ii = 0; ii < pairsIOsrc.length; ii++) { if(trig == singlesIOsrc[ii]) { singlesEn[ii] = true; @@ -160,50 +308,60 @@ } } } - - // GENERAL CASE: - // Append trigger# onto key: + + // GENERAL CASE: Basic Parameter + // This indicates a regular parameter that does not + // require any special parsing. if(vals.size() > 1 && key.startsWith("SSP")) { + // List the parameter by "[ROW NAME]_[KEY]" and + // remove the key so that only the values remain. key += "_" + vals.remove(0); } - // dump it into the map: + + // Add the parameter key and its values to the map. configMap.put(key, vals); } } } - /* - * This function parses the config map for the cases where the - * config string has a simple format: - * TAG VALUE - * TAG TRIGGER VALUES + /** + * Parses the configuration parameter map entries and extracts the + * parameter values for those parameters which have the standard + * format of <code>[PARAMETER KEY] --> { [PARAMETER VALUES] }</code>. */ public void parseConfigMap() { - fadcNSA = Integer.valueOf(getConfig("FADC250_NSA", 0)); - fadcNSB = Integer.valueOf(getConfig("FADC250_NSB", 0)); - fadcNPEAK = Integer.valueOf(getConfig("FADC250_NPEAK", 0)); - fadcMODE = Integer.valueOf(getConfig("FADC250_MODE", 0)); - fadcWIDTH = Integer.valueOf(getConfig("FADC250_W_WIDTH", 0)); - fadcOFFSET = Integer.valueOf(getConfig("FADC250_W_OFFSET", 0)); - - gtpMinSeedEnergy = Integer.valueOf(getConfig("GTP_CLUSTER_PULSE_THRESHOLD", 0)); - gtpWindowBefore = Integer.valueOf(getConfig("GTP_CLUSTER_PULSE_COIN", 0)); - gtpWindowAfter = Integer.valueOf(getConfig("GTP_CLUSTER_PULSE_COIN", 1)); - + // Parse simple FADC data. + fadcNSA = Integer.valueOf(getConfigParameter("FADC250_NSA", 0)); + fadcNSB = Integer.valueOf(getConfigParameter("FADC250_NSB", 0)); + fadcNPEAK = Integer.valueOf(getConfigParameter("FADC250_NPEAK", 0)); + fadcMODE = Integer.valueOf(getConfigParameter("FADC250_MODE", 0)); + fadcWIDTH = Integer.valueOf(getConfigParameter("FADC250_W_WIDTH", 0)); + fadcOFFSET = Integer.valueOf(getConfigParameter("FADC250_W_OFFSET", 0)); + + // Parse GTP data. + gtpMinSeedEnergy = Integer.valueOf(getConfigParameter("GTP_CLUSTER_PULSE_THRESHOLD", 0)); + gtpWindowBefore = Integer.valueOf(getConfigParameter("GTP_CLUSTER_PULSE_COIN", 0)); + gtpWindowAfter = Integer.valueOf(getConfigParameter("GTP_CLUSTER_PULSE_COIN", 1)); + + // Parse trigger data. for(int ii = 0; ii < 2; ii++) { + // Check singles trigger cuts enabled status. singlesNhitsEn[ii] = getBoolConfigSSP(ii, "SINGLES_NMIN", 1); singlesEnergyMinEn[ii] = getBoolConfigSSP(ii, "SINGLES_EMIN", 1); singlesEnergyMaxEn[ii] = getBoolConfigSSP(ii, "SINGLES_EMAX", 1); + // Check pair trigger cuts enabled status. pairsEnergySumMaxMinEn[ii] = getBoolConfigSSP(ii, "PAIRS_SUMMAX_MIN", 2); pairsEnergyDiffEn[ii] = getBoolConfigSSP(ii, "PAIRS_DIFFMAX", 1); pairsCoplanarityEn[ii] = getBoolConfigSSP(ii, "PAIRS_COPLANARITY", 1); pairsEnergyDistEn[ii] = getBoolConfigSSP(ii, "PAIRS_ENERGYDIST", 2); + // Get the singles trigger cuts. singlesNhits[ii] = getIntConfigSSP(ii, "SINGLES_NMIN", 0); singlesEnergyMin[ii] = getIntConfigSSP(ii, "SINGLES_EMIN", 0); singlesEnergyMax[ii] = getIntConfigSSP(ii, "SINGLES_EMAX", 0); + // Get the pair trigger cuts. pairsNhitsMin[ii] = getIntConfigSSP(ii, "PAIRS_NMIN", 0); pairsEnergyMin[ii] = getIntConfigSSP(ii, "PAIRS_EMIN", 0); pairsEnergyMax[ii] = getIntConfigSSP(ii, "PAIRS_EMAX", 0); @@ -217,20 +375,18 @@ } } - - - /* - * UNFINISHED. - * This is a fixer-upper for before we had the full config in EVIO - * or when there was a bug in it. + /** + * Method corrects parameter data for runs that either did not + * correctly record the full configuration data or were bugged. + * It populates missing fields with a zero value entry. + * @param runNumber - The run number for the current run. This is + * used to determine if the run is a "bugged" run. */ private void fixConfigMap2014Run(int runNumber) { + // If this is a good run, noting should be done. Return. if(runNumber > 3470 || runNumber < 3100) { return; } - // TODO: port datacat/python/engrun/engrun_metadata.py - // 1. SET GTP SETTINGS MANUALLY BASED ON RUN NUMBER - // 2. FIX SINGLES_NMIN prior to 3312 - for (String key : configMap.keySet()) { - } + + // Populate missing GTP entries. List<String> tmp = new ArrayList<String>(); tmp.add("0"); tmp.add("0"); @@ -238,41 +394,90 @@ tmp.add("0"); configMap.put("GTP_CLUSTER_THRESH" ,tmp); configMap.put("GTP_TIMEDIFF", tmp); - } - - /* - * These treat the FADC config lines with 16+1 columns. - * Must keep track of most recent FADC250_SLOT tag, since it's - * not on the line with the data. + + // TODO: Port datacat/python/engrun/engrun_metadata.py + // 1. SET GTP SETTINGS MANUALLY BASED ON RUN NUMBER + // 2. FIX SINGLES_NMIN prior to 3312 + } + + /** + * Parses FADC configuration parameter entries. These all have 17 + * lines, the first of which is the parameter key and the subsequent + * being parameter values corresponding to the 16 FADC channels for + * the indicated FADC slot. These entries contain thresholds, gains, + * and pedestals. + * @param crate - The crate associated with this parameter entry. + * @param key - The parameter key. + * @param vals - A list of 16 values with indices corresponding to + * the FADC channel with which they are associated. */ private void parseFADC(int crate, String key, List<String> vals) { - // System.out.println(crate); - if (key.equals("FADC250_SLOT")) { + // The FADC slot is not stored on the same line as the other + // data and must be parsed and retained, as it is necessary + // for handling the subsequent lines. If this line is the + // FADC slot, store it. + if(key.equals("FADC250_SLOT")) { thisFadcSlot = Integer.valueOf(vals.get(0)); } - else if (key.equals("FADC250_ALLCH_TET")) { + + // Parse the channel thresholds. + else if(key.equals("FADC250_ALLCH_TET")) { setChannelParsInt(crate, thisFadcSlot, THRESHOLD, vals); } - else if (key.equals("FADC250_ALLCH_PED")) { + + // Parse the channel pedestals. + else if(key.equals("FADC250_ALLCH_PED")) { setChannelParsFloat(crate, thisFadcSlot, PEDESTAL, vals); } - else if (key.equals("FADC250_ALLCH_GAIN")) { + + // Parse the channel gains. + else if(key.equals("FADC250_ALLCH_GAIN")) { setChannelParsFloat(crate, thisFadcSlot, GAIN, vals); } } - private void setChannelParsFloat(int crate, int slot, Map<EcalChannel, Float>map, List<String> vals) { - for (int ii = 0; ii < 16; ii++) { - map.put(findChannel(crate, slot, ii),Float.valueOf(vals.get(ii))); - } - } - - private void setChannelParsInt(int crate, int slot, Map<EcalChannel, Integer>map, List<String> vals) { - for (int ii = 0; ii < 16; ii++) { - map.put(findChannel(crate, slot, ii),Integer.valueOf(vals.get(ii))); - } - } - + /** + * Takes a list of 16 values (in argument <code>vals</code>) and + * maps the appropriate database calorimeter channel to the list + * value. This assumes that the <code>String</code> values should + * be parsed to <code>Float</code> objects. + * @param crate - The calorimeter crate associated with the values. + * @param slot - The FADC slot associated with the values. + * @param map - The map in which to place the values. + * @param vals - A <code>List</code> of 16 <code>String</code> + * objects representing the channel values. This should correspond + * to FADC channels 0 - 15. + */ + private void setChannelParsFloat(int crate, int slot, Map<EcalChannel, Float> map, List<String> vals) { + // Iterate over each channel and map the database channel object + // to the corresponding list value. + for(int ii = 0; ii < 16; ii++) { + map.put(findChannel(crate, slot, ii), Float.valueOf(vals.get(ii))); + } + } + + /** + * Takes a list of 16 values (in argument <code>vals</code>) and + * maps the appropriate database calorimeter channel to the list + * value. This assumes that the <code>String</code> values should + * be parsed to <code>Integer</code> objects. + * @param crate - The calorimeter crate associated with the values. + * @param slot - The FADC slot associated with the values. + * @param map - The map in which to place the values. + * @param vals - A <code>List</code> of 16 <code>String</code> + * objects representing the channel values. + */ + private void setChannelParsInt(int crate, int slot, Map<EcalChannel, Integer> map, List<String> vals) { + // Iterate over each channel and map the database channel object + // to the corresponding list value. + for(int ii = 0; ii < 16; ii++) { + map.put(findChannel(crate, slot, ii), Integer.valueOf(vals.get(ii))); + } + } + + /** + * Prints the mapped parameter keys and values to the terminal. + */ public void printMap() { System.out.print("\nTriggerConfigMap::::::::::::::::::::::::::::\n"); for (String key : configMap.keySet()) { @@ -285,8 +490,10 @@ System.out.println("::::::::::::::::::::::::::::::::::::::::::::"); } - public void printVars() - { + /** + * Prints the parsed parameter values to the terminal. + */ + public void printVars() { System.out.println("\nTriggerConfigVars%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); System.out.println(); System.out.println(String.format("GTPMINSEED: %d", gtpMinSeedEnergy)); @@ -300,7 +507,6 @@ System.out.println(String.format("FADC250_WIDTH: %d", fadcWIDTH)); System.out.println(String.format("FADC250_OFFSET: %d", fadcOFFSET)); for(EcalChannel cc : ecalConditions.getChannelCollection()) { - //System.out.print(String.format("SLOT%d CHAN%d --",cc.getSlot(),cc.getChannel())); if(!PEDESTAL.containsKey(cc)) { System.out.println("\nP !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } @@ -310,8 +516,6 @@ if(!GAIN.containsKey(cc)) { System.out.println("\nG !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } - //System.out.println(String.format(" %f %d %f", - // PEDESTAL.get(cc),THRESHOLD.get(cc),GAIN.get(cc))); } System.out.println(); @@ -345,55 +549,138 @@ System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); } - /* - * Parsing wrappers to make rest of code easier. + /** + * Gets an SSP parameter value using a shortened version of the + * full parameter key and parses it as a <code>float</code>. + * @param itrig - The number of the trigger for which to obtain + * the parameter value. + * @param stub - The shortened version of the parameter key. This + * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]". + * @param ival - The index of the value that is to be obtained. + * @return Returns the requested value if it exists. Otherwise, a + * value of <code>0</code> is returned and a message is logged. */ public float getFloatConfigSSP(int itrig, String stub, int ival) { return Float.valueOf(getConfigSSP(itrig, stub, ival)); } + /** + * Gets an SSP parameter value using a shortened version of the + * full parameter key and parses it as a <code>int</code>. + * @param itrig - The number of the trigger for which to obtain + * the parameter value. + * @param stub - The shortened version of the parameter key. This + * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]". + * @param ival - The index of the value that is to be obtained. + * @return Returns the requested value if it exists. Otherwise, a + * value of <code>0</code> is returned and a message is logged. + */ public int getIntConfigSSP(int itrig, String stub, int ival) { return Integer.valueOf(getConfigSSP(itrig, stub, ival)); } + /** + * Gets an SSP parameter value using a shortened version of the + * full parameter key and parses it as a <code>boolean</code>. + * @param itrig - The number of the trigger for which to obtain + * the parameter value. + * @param stub - The shortened version of the parameter key. This + * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]". + * @param ival - The index of the value that is to be obtained. + * @return Returns the requested value if it exists. Otherwise, a + * value of <code>false</code> is returned and a message is logged. + */ public boolean getBoolConfigSSP(int itrig, String stub, int ival) { return "1".equals(getConfigSSP(itrig, stub, ival)); } + /** + * Gets an SSP parameter value using a shortened version of the + * full parameter key. + * @param itrig - The number of the trigger for which to obtain + * the parameter value. + * @param stub - The shortened version of the parameter key. This + * corresponds to "SSP_HPS_[STUB]_[TRIGGER NUMBER]". + * @param ival - The index of the value that is to be obtained. + * @return Returns the requested value if it exists. Otherwise, a + * value of <code>"0"</code> is returned and a message is logged. + */ public String getConfigSSP(int itrig, String stub, int ival) { String key = "SSP_HPS_" + stub + "_" + itrig; - return getConfig(key,ival); - } - - public String getConfig(String key, int ival) { - if (configMap.containsKey(key)) { + return getConfigParameter(key, ival); + } + + /** + * Gets a parameter value associated with a parameter key. + * @param key - The parameter key to which the value belongs. + * @param ival - The index of the desired parameter value. + * @return Returns the requested parameter value if it exists and + * returns <code>"0"</code> otherwise. In the event that a parameter + * can not be found, an error message is passed to the logger. + */ + public String getConfigParameter(String key, int ival) { + // Check the parameter map for the requested parameter key. + if(configMap.containsKey(key)) { + // Get the list of values associated with this parameter key. List<String> vals = configMap.get(key); - if (ival < vals.size()) { - return configMap.get(key).get(ival); - } else { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, - "ConfigMap TOO SHORT: " + ival + " " + configMap.get(key)); + + // Check that the list of values contains a parameter for + // the requested parameter index. If it does, return it. + if (ival < vals.size()) { return configMap.get(key).get(ival); } + + // Otherwise, an error has occurred. Log this and return the + // default value of zero. + else { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "ConfigMap TOO SHORT: " + ival + " " + configMap.get(key)); return "0"; } - } else { - // this is only necessarily an error if we've read 3 banks: + } + + // If the key is not present... + else { + // If more than 2 banks have been read, the absence of a + // key represents an error. Log that this has occurred. if(nBanks > 2) { Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "ConfigMap MISSING KEY: " + key); } + + // Return a default value of zero. return "0"; } } + /** + * Gets the database calorimeter channel for a channel defined by + * a crate number, FADC slot, and FADC channel. + * @param crate - The crate number. + * @param fadcSlot - The FADC slot. + * @param fadcChan - The FADC channel. + * @return Returns the database channel as a <code>EcalChannel</code> + * if it exists, and <code>null</code> if it does not. + */ public EcalChannel findChannel(int crate, int fadcSlot, int fadcChan) { + // Search through the database channels for a channel that + // matches the the argument parameters. for (EcalChannel cc : channels) { - // EcalChannel follows different convention on crate numbering: - if ((cc.getCrate() - 1) * 2 == crate - 37 && cc.getSlot() == fadcSlot && cc.getChannel() == fadcChan) { + // A channel matches the argument if the slot and channel + // values are the same. Crate number must also match, but + // note that EcalChannel follows a different convention + // with respect to crate numbering. + if( ((cc.getCrate() - 1) * 2 == crate - 37) && (cc.getSlot() == fadcSlot) && (cc.getChannel() == fadcChan) ) { return cc; } } + + // If no matching channel is found, return null. return null; } + /** + * Gets the database crystal channel object based on the crystal's + * numerical index. + * @param channel_id - The crystal index. + * @return Returns the channel as an <code>EcalChannel</code>. + */ public EcalChannel findChannel(int channel_id) { return ecalConditions.getChannelCollection().findChannel(channel_id); } Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/AbstractIntData.java Thu Aug 6 17:19:42 2015 @@ -4,57 +4,64 @@ import org.lcsim.event.GenericObject; /** - * GenericObject representation of an INT32/UINT32 bank read from EVIO. The bank - * header tag identifies the type of data, and is stored as the first int in the - * GenericObject. The contents of the bank are the remaining N-1 ints. - * Constructors are provided from int[] (for reading from EVIO) and from - * GenericObject (for reading from LCIO). - * + * Class <code>GenericObject</code> representation of an INT32/UINT32 + * bank read from EvIO. The bank header tag identifies the type of + * data, and is stored as the first int in the <code>GenericObject</code>. + * The contents of the bank are the remaining N-1 <code>int</code> + * primitives. Constructors are provided from <code>int[]</code> (for + * reading from EvIO) and from <code>GenericObject</code> (for reading + * from LCIO).<br/> + * <br/> * Subclasses must implement the two constructors and two abstract methods, plus * whatever methods are needed to access the parsed data. * * @author Sho Uemura <[log in to unmask]> - * @version $Id: $ + * @see GenericObject */ public abstract class AbstractIntData implements GenericObject { - + /** The data bank. */ protected int[] bank; - + /** - * Constructor from EVIO int bank. Bank tag must be checked by EVIO reader - * before the constructor is called. - * - * @param bank + * Constructs an <code>AbstractIntData</code> from a raw EvIO integer + * bank. It is expected that the EvIO reader will verify that the + * bank tag is the appropriate type before calling the constructor. + * @param bank - An EvIO bank of <code>int</code> data. */ protected AbstractIntData(int[] bank) { - if (bank == null) { - this.bank = new int[0]; - } else { - this.bank = Arrays.copyOf(bank, bank.length); - } + if(bank == null) { this.bank = new int[0]; } + else { this.bank = Arrays.copyOf(bank, bank.length); } } - + /** - * Constructor from LCIO GenericObject. Checks the bank tag; subclass - * constructor must set the expected value of the tag. - * - * @param data - * @param expectedTag + * Create an <code>AbstractIntData</code> object from an LCIO + * <code>genericObject</code>. Constructor requires that the + * <code>GenericObject</code> tag match the expected EvIO header + * tag type as defined by the implementing class. + * @param data - The source data bank. + * @param expectedTag - The required EvIO bank header tag. */ protected AbstractIntData(GenericObject data, int expectedTag) { - if (getTag(data) != expectedTag) { + // If the EvIO bank header tag is not the required type, + // produce an exception. + if(getTag(data) != expectedTag) { throw new RuntimeException("expected tag " + expectedTag + ", got " + getTag(data)); } + + // Otherwise, store the bank. this.bank = getBank(data); } - + + /** + * Gets the entire, unparsed integer data bank from the object. + * @return Returns the data as an <code>int[]</code> array. + */ public int[] getBank() { return bank; } - + /** * Return the int bank of an AbstractIntData read from LCIO. - * * @param object * @return */ @@ -66,55 +73,55 @@ } return bank; } - + /** - * Return a single value from the int bank of an AbstractIntData. - * - * @param object - * @param index - * @return + * Return a single value from the integer bank of an + * <code>AbstractIntData</code>. + * @param object - The bank from which to obtain the data. + * @param index - The index of the data in the bank. + * @return Returns the requested entry from the integer bank. */ public static int getBankInt(GenericObject object, int index) { return object.getIntVal(index + 1); } - + /** - * Returns the EVIO bank header tag expected for this data. - * - * @return + * Returns the EvIO bank header tag expected for this data. + * @return Returns the tag as an <code>int</code> primitive. */ public abstract int getTag(); - + /** * Returns the EVIO bank tag for a data object. - * - * @param data - * @return + * @param data - A <code>GenericObject</code> representing an integer + * data bank. + * @return Returns the EvIO tag identifying the type of bank the object + * represents. */ public static int getTag(GenericObject data) { return data.getIntVal(0); } - + /** * Parses the bank so the object can be used in analysis. */ protected abstract void decodeData(); - + @Override public int getNInt() { return bank.length + 1; } - + @Override public int getNFloat() { return 0; } - + @Override public int getNDouble() { return 0; } - + @Override public int getIntVal(int index) { if (index == 0) { @@ -122,19 +129,19 @@ } return bank[index - 1]; } - + @Override public float getFloatVal(int index) { throw new UnsupportedOperationException("No float values in " + this.getClass().getSimpleName()); } - + @Override public double getDoubleVal(int index) { throw new UnsupportedOperationException("No double values in " + this.getClass().getSimpleName()); } - + @Override public boolean isFixedSize() { return true; } -} +} Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/SSPCluster.java Thu Aug 6 17:19:42 2015 @@ -7,7 +7,14 @@ /** * Class <code>SSPCluster</code> stores all of the information on - * clusters that is reported by the SSP. + * clusters that is reported by the SSP. SSP clusters store: + * <ul><li>Cluster center x-index</li> + * <li>Cluster center y-index</li> + * <li>Cluster total energy</li> + * <li>Cluster hit count</li> + * <li>Cluster time</li></ul> + * <code>SSPCluster</code> does not support the ability to track + * individual hits that are part of a cluster. * * @author Kyle McCarty <[log in to unmask]> */ Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TIData.java Thu Aug 6 17:19:42 2015 @@ -2,17 +2,22 @@ import org.lcsim.event.GenericObject; -//import org.hps.record.evio.EvioEventConstants; // doesn't work /** - * TI Trigger Data + * Class <code>TIData</code> is an implementation of abstract class + * <code>AbstractIntData</code> that represents a TI trigger bit bank. + * It contains both a time window length and a set of flags that track + * whether a trigger of a given type was registered with the event to + * which this bank is attached. * * @author Nathan Baltzell <[log in to unmask]> */ public class TIData extends AbstractIntData { - + /** The EvIO bank header tag for TI data banks. */ public static final int BANK_TAG = 0xe10a; // EvioEventConstants.TI_TRIGGER_BANK_TAG; + /** The expected number of entries in the data bank. */ public static final int BANK_SIZE = 4; - + + // Store the parsed data bank parameters. private long time = 0; private boolean singles0 = false; private boolean singles1 = false; @@ -20,69 +25,122 @@ private boolean pairs1 = false; private boolean calib = false; private boolean pulser = false; - + + /** + * Creates a <code>TIData</code> bank from a raw EvIO data bank. + * It is expected that the EvIO reader will verify that the bank + * tag is of the appropriate type. + * @param bank - The EvIO data bank. + */ public TIData(int[] bank) { super(bank); decodeData(); } - + + /** + * Creates a <code>TIData</code> object from an existing LCIO + * <code>GenericObject</code>. + * @param tiData - The source data bank object. + */ public TIData(GenericObject tiData) { super(tiData, BANK_TAG); decodeData(); } - + @Override protected final void decodeData() { - if (this.bank.length != BANK_SIZE) { + // Check that the data bank is the expected size. If not, throw + // and exception. + if(this.bank.length != BANK_SIZE) { throw new RuntimeException("Invalid Data Length: " + bank.length); } - + + // Check each trigger bit to see if it is active. A value of + // 1 indicates a trigger of that type occurred, and 0 that it + // did not. singles0 = ((bank[0] >> 24) & 1) == 1; singles1 = ((bank[0] >> 25) & 1) == 1; pairs0 = ((bank[0] >> 26) & 1) == 1; pairs1 = ((bank[0] >> 27) & 1) == 1; calib = ((bank[0] >> 28) & 1) == 1; pulser = ((bank[0] >> 29) & 1) == 1; - + + // Get the unprocessed start and end times for the bank. long w1 = bank[2] & 0xffffffffL; long w2 = bank[3] & 0xffffffffL; - + + // Process the times into units of clock-cycles. final long timelo = w1; final long timehi = (w2 & 0xffff) << 32; - - time = 4 * (timelo + timehi); // units ns + + // Store the time difference in nanoseconds. + time = 4 * (timelo + timehi); } - + @Override public int getTag() { return BANK_TAG; } - + + /** + * Gets the time window for the bank. + * @return Returns the time window length in nanoseconds. + */ public long getTime() { return time; } - + + /** + * Indicates whether a singles 0 trigger was registered. + * @return Returns <code>true</code> if the trigger occurred, and + * <code>false</code> otherwise. + */ public boolean isSingle0Trigger() { return singles0; } - + + /** + * Indicates whether a singles 1 trigger was registered. + * @return Returns <code>true</code> if the trigger occurred, and + * <code>false</code> otherwise. + */ public boolean isSingle1Trigger() { return singles1; } - + + /** + * Indicates whether a pair 0 trigger was registered. + * @return Returns <code>true</code> if the trigger occurred, and + * <code>false</code> otherwise. + */ public boolean isPair0Trigger() { return pairs0; } - + + /** + * Indicates whether a pair 1 trigger was registered. + * @return Returns <code>true</code> if the trigger occurred, and + * <code>false</code> otherwise. + */ public boolean isPair1Trigger() { return pairs1; } - + + /** + * Indicates whether a cosmic trigger was registered. + * @return Returns <code>true</code> if the trigger occurred, and + * <code>false</code> otherwise. + */ public boolean isCalibTrigger() { return calib; } - + + /** + * Indicates whether a random/pulser trigger was registered. + * @return Returns <code>true</code> if the trigger occurred, and + * <code>false</code> otherwise. + */ public boolean isPulserTrigger() { return pulser; } -} +} Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/TriggerModule.java Thu Aug 6 17:19:42 2015 @@ -20,62 +20,85 @@ * called without initializing an instance of the module.<br/> * <br/> * Both <code>Cluster</code> objects and <code>SSPCluster</code> objects - * are supported. - * + * are supported, except for the seed energy cut, as this value is not + * present in <code>SSPCluster</code> objects.<br/> + * <br/> + * This module supports the following cuts: + * <ul><li>Seed Energy Lower Bound</li> + * <li>Seed Energy Lower Bound</li> + * <li>Seed Energy Upper Bound</li> + * <li>Cluster Total Energy Upper Bound</li> + * <li>Cluster Total Energy Lower Bound</li> + * <li>Cluster Hit Count Lower Bound</li> + * <li>Pair Energy Sum Upper Bound</li> + * <li>Pair Energy Sum Lower Bound</li> + * <li>Pair Energy Difference Upper Bound</li> + * <li>Pair Energy Slope Lower Bound</li> + * <li>Pair Coplanarity Upper Bound</li> + * <li>Pair Time Coincidence Upper Bound</li></ul> * @author Kyle McCarty <[log in to unmask]> * @see Cluster * @see SSPCluster */ public final class TriggerModule { - // The calorimeter mid-plane, defined by the photon beam position - // (30.52 mrad) at the calorimeter face (z = 1393 mm). + /** The calorimeter mid-plane, defined by the photon beam position + * (30.52 mrad) at the calorimeter face (z = 1393 mm). */ private static final double ORIGIN_X = 1393.0 * Math.tan(0.03052); - // Trigger module property names. /** The value of the parameter "F" in the energy slope equation - * <code>E_low GeV + R_min mm * F GeV/mm</code>. */ + * <code>E_low GeV + R_min mm * F GeV/mm</code>. Units are in GeV + * / mm. */ public static final String PAIR_ENERGY_SLOPE_F = "pairEnergySlopeF"; /** The lower bound for the pair energy sum cut. The sum of the - * energies of two clusters must exceed this value to pass the cut. */ + * energies of two clusters must exceed this value to pass the cut. + * Units are in GeV. */ public static final String PAIR_ENERGY_SUM_LOW = "pairEnergySumLow"; /** The upper bound for the pair energy sum cut. The sum of the - * energies of two clusters must be below this value to pass the cut. */ + * energies of two clusters must be below this value to pass the + * cut. Units are in GeV. */ public static final String PAIR_ENERGY_SUM_HIGH = "pairEnergySumHigh"; /** The threshold for the cluster hit count cut. Clusters must have * this many hits or more to pass the cut. */ public static final String CLUSTER_HIT_COUNT_LOW = "clusterHitCountLow"; /** The threshold for the energy slope cut. The value of the energy - * slope equation must exceed this value to pass the cut. */ + * slope equation must exceed this value to pass the cut. Units are + * in GeV. */ public static final String PAIR_ENERGY_SLOPE_LOW = "pairEnergySlopeLow"; /** The bound for the coplanarity cut. The coplanarity angle for - * the cluster pair must be below this value to pass the cut. */ + * the cluster pair must be below this value to pass the cut. Units + * are in degrees. */ public static final String PAIR_COPLANARITY_HIGH = "pairCoplanarityHigh"; /** The lower bound for the cluster seed energy cut. The seed energy - * of a cluster must exceed this value to pass the cut. */ + * of a cluster must exceed this value to pass the cut. Units are in + * GeV. */ public static final String CLUSTER_SEED_ENERGY_LOW = "clusterSeedEnergyLow"; /** The upper bound for the cluster seed energy cut. The seed energy - * of a cluster must be below this value to pass the cut. */ + * of a cluster must be below this value to pass the cut. Units are + * in GeV. */ public static final String CLUSTER_SEED_ENERGY_HIGH = "clusterSeedEnergyHigh"; /** The lower bound for the cluster total energy cut. The energy * of a cluster must exceed this value to pass the cut. */ public static final String CLUSTER_TOTAL_ENERGY_LOW = "clusterTotalEnergyLow"; /** The upper bound for the cluster total energy cut. The energy - * of a cluster must be below this value to pass the cut. */ + * of a cluster must be below this value to pass the cut. Units are + * in GeV. */ public static final String CLUSTER_TOTAL_ENERGY_HIGH = "clusterTotalEnergyHigh"; /** The bound for the pair energy difference cut. The absolute value * of the difference between the energies of the cluster pair must - * be below this value to pass the cut. */ + * be below this value to pass the cut. Units are in GeV. */ public static final String PAIR_ENERGY_DIFFERENCE_HIGH = "pairEnergyDifferenceHigh"; /** The maximum amount of time by which two clusters are allowed - * to be separated. */ + * to be separated. Units are in ns. */ public static final String PAIR_TIME_COINCIDENCE = "pairTimeCoincidence"; - // Trigger cut settings map. + /** Stores each of the cut values used by the module. Map keys are + * defined as publicly-accessible static variables in the class. */ private final Map<String, Double> cuts = new HashMap<String, Double>(11); /** - * Creates an <code>SSPTriggerModule</code> that accepts all single - * cluster and cluster pair events. + * Creates a default <code>TriggerModule</code>. The cuts are + * defined such that all physical clusters (i.e. with energy + * above zero) will be accepted. */ public TriggerModule() { // Set the cluster singles cuts to accept all values by default. @@ -98,21 +121,21 @@ } /** - * Creates an <code>SSPTriggerModule</code> that uses the default - * cut values specified by the argument array. The array should be - * of size 11. Values are applied in the order: + * Creates a <code>TriggerModule</code> with trigger cuts defined + * by the argument array. The order of the cut value arguments are + * as follows: * <ul> - * <li>Cluster Hit Count Lower Bound</li> - * <li>Cluster Seed Energy Lower Bound</li> - * <li>Cluster Seed Energy Upper Bound</li> - * <li>Cluster Seed Total Lower Bound</li> - * <li>Cluster Seed Total Upper Bound</li> - * <li>Pair Energy Sum Lower Bound</li> - * <li>Pair Energy Sum Upper Bound</li> - * <li>Pair Energy Difference Upper Bound</li> - * <li>Pair Energy Slope Lower Bound</li> - * <li>Pair Coplanarity Upper Bound</li> - * <li>Pair Energy Slope Parameter F</li> + * <li>Cluster Hit Count Lower Bound (Hits)</li> + * <li>Cluster Seed Energy Lower Bound (GeV)</li> + * <li>Cluster Seed Energy Upper Bound (GeV)</li> + * <li>Cluster Seed Total Lower Bound (GeV)</li> + * <li>Cluster Seed Total Upper Bound (GeV)</li> + * <li>Pair Energy Sum Lower Bound (GeV)</li> + * <li>Pair Energy Sum Upper Bound (GeV)</li> + * <li>Pair Energy Difference Upper Bound (GeV)</li> + * <li>Pair Energy Slope Lower Bound (GeV)</li> + * <li>Pair Coplanarity Upper Bound (Degrees)</li> + * <li>Pair Energy Slope Parameter F (GeV / mm)</li> * </ul> */ public TriggerModule(double... cutValues) { @@ -139,9 +162,11 @@ /** * Gets the value of the requested cut, if it exists. - * @param cut - The identifier of the cut. + * @param cut - The identifier of the cut. This can be obtained + * through the publicly-accessible static identifiers in this class. * @return Returns the cut value as a <code>double</code>. - * @throws IllegalArgumentException Occurs if the cut does not exist. + * @throws IllegalArgumentException Occurs if the cut identifier + * specified in the argument is not valid. */ public double getCutValue(String cut) throws IllegalArgumentException { // Try to get the indicated cut. @@ -156,8 +181,9 @@ /** * Loads triggers settings from the DAQ configuration for a singles - * trigger. Pair trigger settings will be set to accept all possible - * values, while singles trigger settings will + * trigger. Singles trigger cuts will be set to match those defined + * in the configuration object, while pair trigger cuts will be set + * to accept all possible clusters. * @param config - The DAQ configuration settings. */ public void loadDAQConfiguration(SinglesTriggerConfig config) { @@ -205,11 +231,14 @@ } /** - * Sets the value of the indicated cut to a new value. + * Sets the value of the cut specified by the identifier given in + * the argument to the specified value. * @param cut - The identifier of the cut to which the new value - * should be assigned. + * should be assigned. These can be obtained as publicly-accessible + * static variables from this class. * @param value - The new cut value. - * @throws IllegalArgumentException Occurs if the cut does not exist. + * @throws IllegalArgumentException Occurs if the argument cut + * identifier is not valid. */ public void setCutValue(String cut, double value) throws IllegalArgumentException { // Make sure that the cut exists. If it does, change it to the @@ -230,6 +259,7 @@ * @param cutValues - A string representing the cuts values. This * must be formatted in the style of "Emin Emax Nmin ...". */ + // TODO: Specify in JavaDoc what the order of these arguments is. public void setCutValues(boolean isSingles, String cutValues) { // Make sure that the string is not null. if(cutValues == null) { @@ -283,8 +313,8 @@ } /** - * Checks whether the argument cluster possesses the minimum - * allowed hits. + * Checks whether a cluster passes the cluster hit count cut. This + * is defined as <code>N_hits >= CLUSTER_HIT_COUNT_LOW</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -294,8 +324,8 @@ } /** - * Checks whether the argument cluster possesses the minimum - * allowed hits. + * Checks whether a cluster passes the cluster hit count cut. This + * is defined as <code>N_hits >= CLUSTER_HIT_COUNT_LOW</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -305,8 +335,9 @@ } /** - * Checks whether the argument cluster seed hit falls within the - * allowed seed hit energy range. + * Checks whether a cluster passes the seed energy cut. This is + * defined as <code>CLUSTER_SEED_ENERGY_LOW <= E_seed <= + * CLUSTER_SEED_ENERGY_HIGH</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -316,8 +347,8 @@ } /** - * Checks whether the argument cluster seed hit falls below the - * allowed seed hit energy upper bound. + * Checks whether a cluster passes the seed energy upper bound cut. + * This is defined as <code>E_seed <= CLUSTER_SEED_ENERGY_HIGH</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -327,8 +358,8 @@ } /** - * Checks whether the argument cluster seed hit falls above the - * allowed seed hit energy lower bound. + * Checks whether a cluster passes the seed energy lower bound cut. + * This is defined as <code>CLUSTER_SEED_ENERGY_LOW <= E_seed</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -338,8 +369,9 @@ } /** - * Checks whether the argument cluster falls within the allowed - * cluster total energy range. + * Checks whether a cluster passes the cluster total energy cut. + * This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <= E_cluster + * <= CLUSTER_TOTAL_ENERGY_HIGH</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -349,8 +381,9 @@ } /** - * Checks whether the argument cluster falls below the allowed - * cluster total energy upper bound. + * Checks whether a cluster passes the cluster total energy upper + * bound cut. This is defined as <code>E_cluster <= + * CLUSTER_TOTAL_ENERGY_HIGH</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -360,8 +393,9 @@ } /** - * Checks whether the argument cluster falls above the allowed - * cluster total energy lower bound. + * Checks whether a cluster passes the cluster total energy lower + * bound cut. This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <= + * E_cluster</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -371,8 +405,9 @@ } /** - * Checks whether the argument cluster falls within the allowed - * cluster total energy range. + * Checks whether a cluster passes the cluster total energy cut. + * This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <= E_cluster + * <= CLUSTER_TOTAL_ENERGY_HIGH</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -382,8 +417,9 @@ } /** - * Checks whether the argument cluster falls below the allowed - * cluster total energy upper bound. + * Checks whether a cluster passes the cluster total energy upper + * bound cut. This is defined as <code>E_cluster <= + * CLUSTER_TOTAL_ENERGY_HIGH</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -393,8 +429,9 @@ } /** - * Checks whether the argument cluster falls above the allowed - * cluster total energy lower bound. + * Checks whether a cluster passes the cluster total energy lower + * bound cut. This is defined as <code>CLUSTER_TOTAL_ENERGY_LOW <= + * E_cluster</code>. * @param cluster - The cluster to check. * @return Returns <code>true</code> if the cluster passes the cut * and <code>false</code> if the cluster does not. @@ -409,6 +446,7 @@ * be calculated. * @return Returns displacement of the cluster. */ + // TODO: What defines cluster distance? public static double getClusterDistance(Cluster cluster) { // Get the variables from the cluster. double x = getClusterX(cluster); @@ -419,12 +457,23 @@ } /** - * Gets the size of a cluster. + * Gets the number of hits in a cluster, as used in the cluster + * hit count cut. * @param cluster - The cluster for which to obtain the size. * @return Returns the size as an <code>int</code>. */ public static final double getClusterHitCount(Cluster cluster) { return cluster.getCalorimeterHits().size(); + } + + /** + * Gets the number of hits in a cluster, as used in the cluster + * hit count cut. + * @param cluster - The cluster for which to obtain the size. + * @return Returns the size as an <code>int</code>. + */ + public static final double getClusterHitCount(SSPCluster cluster) { + return cluster.getHitCount(); } /** @@ -442,12 +491,23 @@ } /** - * Gets the time-stamp of a cluster. + * Gets the time-stamp of a cluster, as used in the time-coincidence + * cut. * @param cluster - The cluster for which to obtain the time. * @return Returns the time as a <code>double</code>. */ public static final double getClusterTime(Cluster cluster) { return getClusterSeedHit(cluster).getTime(); + } + + /** + * Gets the time-stamp of a cluster, as used in the time-coincidence + * cut. + * @param cluster - The cluster for which to obtain the time. + * @return Returns the time as a <code>double</code>. + */ + public static final double getClusterTime(SSPCluster cluster) { + return cluster.getTime(); } /** @@ -471,12 +531,21 @@ } /** - * Gets the x-index of a cluster. + * Gets the x-index of a cluster's * @param cluster - The cluster for which to obtain the index. * @return Returns the index as an <code>int</code>. */ public static final int getClusterXIndex(Cluster cluster) { return getClusterSeedHit(cluster).getIdentifierFieldValue("ix"); + } + + /** + * Gets the x-index of a cluster's + * @param cluster - The cluster for which to obtain the index. + * @return Returns the index as an <code>int</code>. + */ + public static final int getClusterXIndex(SSPCluster cluster) { + return cluster.getXIndex(); } /** @@ -509,6 +578,15 @@ } /** + * Gets the y-index of a cluster. + * @param cluster - The cluster for which to obtain the index. + * @return Returns the index as an <code>int</code>. + */ + public static final int getClusterYIndex(SSPCluster cluster) { + return cluster.getYIndex(); + } + + /** * Gets the z-position of a cluster in millimeters in the hardware * coordinate system. * @param cluster - The cluster of which to get the z-position. @@ -529,27 +607,30 @@ } /** - * Gets the value used for the cluster total energy cut. + * Gets the value used for the cluster total energy cut. This is + * the energy of the entire cluster. * @param cluster - The cluster from which the value should be * derived. - * @return Returns the energy of the entire cluster in GeV. + * @return Returns the cluster energy in GeV. */ public static double getValueClusterTotalEnergy(Cluster cluster) { return cluster.getEnergy(); } /** - * Gets the value used for the cluster total energy cut. + * Gets the value used for the cluster total energy cut. This is + * the energy of the entire cluster. * @param cluster - The cluster from which the value should be * derived. - * @return Returns the energy of the entire cluster in GeV. + * @return Returns the cluster energy in GeV. */ public static double getValueClusterTotalEnergy(SSPCluster cluster) { return cluster.getEnergy(); } /** - * Gets the value used for the cluster hit count cut. + * Gets the value used for the cluster hit count cut. This is the + * total number of hits included in the cluster. * @param cluster - The cluster from which the value should be * derived. * @return Returns the number of hits in the cluster. @@ -559,7 +640,8 @@ } /** - * Gets the value used for the cluster hit count cut. + * Gets the value used for the cluster hit count cut. This is the + * total number of hits included in the cluster. * @param cluster - The cluster from which the value should be * derived. * @return Returns the number of hits in the cluster. @@ -587,14 +669,15 @@ public static double getValueCoplanarity(Cluster[] clusterPair) { // Get the variables used by the calculation. double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) }; - double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) }; + double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) }; // Return the calculated value. - return getValueCoplanarity(x, z); - } - - /** - * Calculates the value used by the coplanarity cut. + return getValueCoplanarity(x, y); + } + + /** + * Calculates the value used by the coplanarity cut. A value of zero + * represents clusters in the same plane. * @param clusterPair - The cluster pair from which the value should * be calculated. * @return Returns the cut value. @@ -602,10 +685,10 @@ public static double getValueCoplanarity(SSPCluster[] clusterPair) { // Get the variables used by the calculation. double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) }; - double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) }; + double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) }; // Return the calculated value. - return getValueCoplanarity(x, z); + return getValueCoplanarity(x, y); } /** @@ -667,10 +750,10 @@ // Get the variables used by the calculation. double[] energy = { clusterPair[0].getEnergy(), clusterPair[1].getEnergy() }; double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) }; - double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) }; + double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) }; // Perform the calculation. - return getValueEnergySlope(energy, x, z, energySlopeParamF); + return getValueEnergySlope(energy, x, y, energySlopeParamF); } /** @@ -685,10 +768,10 @@ // Get the variables used by the calculation. double[] energy = { clusterPair[0].getEnergy(), clusterPair[1].getEnergy() }; double x[] = { getClusterX(clusterPair[0]), getClusterX(clusterPair[1]) }; - double z[] = { getClusterZ(clusterPair[0]), getClusterZ(clusterPair[1]) }; + double y[] = { getClusterY(clusterPair[0]), getClusterY(clusterPair[1]) }; // Perform the calculation. - return getValueEnergySlope(energy, x, z, energySlopeParamF); + return getValueEnergySlope(energy, x, y, energySlopeParamF); } /** @@ -773,7 +856,7 @@ /** * Checks if a cluster pair is coplanar to the beam within a given - * angle. + * angle. This is defined as <code>θ <= PAIR_COPLANARITY_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -784,7 +867,7 @@ /** * Checks if a cluster pair is coplanar to the beam within a given - * angle. + * angle. This is defined as <code>θ <= PAIR_COPLANARITY_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -795,7 +878,8 @@ /** * Checks if the energy difference between the clusters making up - * a cluster pair is below an energy difference threshold. + * a cluster pair is below an energy difference threshold. This is + * defined as <code>|E_1 - E_2| <= PAIR_ENERGY_DIFFERENCE_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -806,7 +890,8 @@ /** * Checks if the energy difference between the clusters making up - * a cluster pair is below an energy difference threshold. + * a cluster pair is below an energy difference threshold. This is + * defined as <code>|E_1 - E_2| <= PAIR_ENERGY_DIFFERENCE_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -818,7 +903,7 @@ /** * Requires that the distance from the beam of the lowest energy * cluster in a cluster pair satisfies the following:<br/> - * <code>E_low + R_min * F < [ Threshold ]</code> + * <code>E_low + R_min * F >= PAIR_ENERGY_SLOPE_LOW</code> * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -830,7 +915,7 @@ /** * Requires that the distance from the beam of the lowest energy * cluster in a cluster pair satisfies the following:<br/> - * <code>E_low + R_min * F < [ Threshold ]</code> + * <code>E_low + R_min * F >= PAIR_ENERGY_SLOPE_LOW</code> * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -841,7 +926,9 @@ /** * Checks if the sum of the energies of the clusters making up a - * cluster pair is within an energy sum threshold. + * cluster pair is within an energy sum threshold. This is defined + * as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2 <= + * PAIR_ENERGY_SUM_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -853,6 +940,7 @@ /** * Checks if the sum of the energies of the clusters making up a * cluster pair is below the energy sum upper bound threshold. + * This is defined as <code>E_1 + E_2 <= PAIR_ENERGY_SUM_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -864,6 +952,7 @@ /** * Checks if the sum of the energies of the clusters making up a * cluster pair is above the energy sum lower bound threshold. + * This is defined as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -874,7 +963,9 @@ /** * Checks if the sum of the energies of clusters making up a cluster - * pair is below an energy sum threshold. + * pair is below an energy sum threshold. This is defined + * as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2 <= + * PAIR_ENERGY_SUM_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -886,6 +977,7 @@ /** * Checks if the sum of the energies of the clusters making up a * cluster pair is below the energy sum upper bound threshold. + * This is defined as <code>E_1 + E_2 <= PAIR_ENERGY_SUM_HIGH</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -897,6 +989,7 @@ /** * Checks if the sum of the energies of the clusters making up a * cluster pair is above the energy sum lower bound threshold. + * This is defined as <code>PAIR_ENERGY_SUM_LOW <= E_1 + E_2</code>. * @param clusterPair - The cluster pair to check. * @return Returns <code>true</code> if the cluster pair passes * the cut and <code>false</code> if it does not. @@ -907,7 +1000,8 @@ /** * Checks if the absolute difference between the times between - * two clusters is below the time coincidence cut. + * two clusters is below the time coincidence cut. This is defined + * as <code>|t_1 - t_2| <= PAIR_TIME_COINCIDENCE</code>. * @param clusterPair - The cluster pair to check. * @return <code>true</code> if the energy sum passes * the cut and <code>false</code> if it does not. @@ -918,7 +1012,8 @@ /** * Checks if the absolute difference between the times between - * two clusters is below the time coincidence cut. + * two clusters is below the time coincidence cut. This is defined + * as <code>|t_1 - t_2| <= PAIR_TIME_COINCIDENCE</code>. * @param clusterPair - The cluster pair to check. * @return <code>true</code> if the energy sum passes * the cut and <code>false</code> if it does not. @@ -1018,9 +1113,8 @@ * Gets the mapped position used by the SSP for a specific crystal. * @param ix - The crystal x-index. * @param iy - The crystal y-index. - * @return Returns the crystal position as a <double</code> array - * where the coordinates are ordered from the lowest to highest - * index as x, y, z. + * @return Returns the crystal position as a <code>double</code> + * array of form { x, y, z }. * @throws IndexOutOfBoundsException Occurs if in either of the * cases where <code>ix == 0</code> or <code>|ix| > 23</code> for * the x-index and either of the cases where <code>iy == 0</code> @@ -1034,9 +1128,13 @@ throw new IndexOutOfBoundsException(String.format("Value \"%d\" is invalid for field y-index.", iy)); } - // Return the mapped position. - if(ix < 1) { return position[5 - iy][22 - ix]; } - else { return position[5 - iy][23 - ix]; } + // Get the position map. + double posMap[]; + if(ix < 1) { posMap = position[5 - iy][22 - ix]; } + else { posMap = position[5 - iy][23 - ix]; } + + // Return the corrected mapped position. + return new double[] { posMap[0], posMap[2], posMap[1] }; } /** @@ -1047,11 +1145,11 @@ * second clusters' y-positions. * @return Returns the cluster pair's coplanarity. */ - private static double getValueCoplanarity(double[] x, double z[]) { + private static double getValueCoplanarity(double[] x, double y[]) { // Get the cluster angles. int[] clusterAngle = new int[2]; for(int i = 0; i < 2; i++) { - clusterAngle[i] = (int) Math.round(Math.atan(x[i] / z[i]) * 180.0 / Math.PI); + clusterAngle[i] = (int) Math.round(Math.atan(x[i] / y[i]) * 180.0 / Math.PI); } // Calculate the coplanarity cut value. @@ -1098,33 +1196,7 @@ * energy slope equation E_low + R_min * F. * @return Returns the cut value. */ - private static double getValueEnergySlope(double energy[], double x[], double z[], double energySlopeParamF) { - // Determine which cluster is the lower-energy cluster. - int lei = energy[0] < energy[1] ? 0 : 1; - - // E + R*F - // Get the low energy cluster energy. - double slopeParamE = energy[lei]; - - // Get the low energy cluster radial distance. - double slopeParamR = Math.sqrt((x[lei] * x[lei]) + (z[lei] * z[lei])); - - // Calculate the energy slope. - return slopeParamE + slopeParamR * energySlopeParamF; - } - - /** - * Calculates the value used by the energy slope cut. This version - * is superseded by the <code>getValueEnergySlope</code>, which - * more accurately mirrors the hardware behavior. - * @param clusterPair - The cluster pair from which the value should - * be calculated. - * @param energySlopeParamF - The value of the variable F in the - * energy slope equation E_low + R_min * F. - * @return Returns the cut value. - */ - @Deprecated - private static double getValueEnergySlopeLegacy(double energy[], double x[], double y[], double energySlopeParamF) { + private static double getValueEnergySlope(double energy[], double x[], double y[], double energySlopeParamF) { // Determine which cluster is the lower-energy cluster. int lei = energy[0] < energy[1] ? 0 : 1; @@ -1140,6 +1212,32 @@ } /** + * Calculates the value used by the energy slope cut. This version + * is superseded by the <code>getValueEnergySlope</code>, which + * more accurately mirrors the hardware behavior. + * @param clusterPair - The cluster pair from which the value should + * be calculated. + * @param energySlopeParamF - The value of the variable F in the + * energy slope equation E_low + R_min * F. + * @return Returns the cut value. + */ + @Deprecated + private static double getValueEnergySlopeLegacy(double energy[], double x[], double y[], double energySlopeParamF) { + // Determine which cluster is the lower-energy cluster. + int lei = energy[0] < energy[1] ? 0 : 1; + + // E + R*F + // Get the low energy cluster energy. + double slopeParamE = energy[lei]; + + // Get the low energy cluster radial distance. + double slopeParamR = Math.sqrt((x[lei] * x[lei]) + (y[lei] * y[lei])); + + // Calculate the energy slope. + return slopeParamE + slopeParamR * energySlopeParamF; + } + + /** * Calculates the value used by the energy sum cut. * @param energy - A two-dimensional array consisting of the first * and second clusters' energies. @@ -1242,7 +1340,10 @@ * the hardware SSP position mappings for each crystal. Note that * ix in the array goes from -22 (representing ix = 23) up to 25 * (representing ix = 23) and uses array index x = 0 as a valid - * parameter, while ix skips zero. + * parameter, while ix skips zero.<br/> + * <br/> + * Note that in this table, position[][] = { x, z, y } by in the + * coordinate system employed by the rest of the class. */ private static final double[][][] position = { { { -340.003, 97.065, 87.845 }, { -324.283, 97.450, 87.875 }, { -308.648, 97.810, 87.900 },