Author: [log in to unmask] Date: Wed Jan 21 17:23:33 2015 New Revision: 1964 Log: Uploaded correct version of the GTP clustering algorithm. Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPClusterer.java 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 Wed Jan 21 17:23:33 2015 @@ -14,60 +14,66 @@ 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>GTPCalorimeterClusterer</code> processes events and + * converts hits into clusters, where appropriate. It uses the modified + * 2014 clustering algorithm.<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/> + * 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/> * <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. + * 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 */ public class GTPClusterer extends AbstractClusterer { /** - * <b>seedEnergyThreshold</b><br/><br/> - * <code>private double <b>seedEnergyThreshold</b></code><br/><br/> - * The minimum energy required for a hit to be considered as a cluster - * center. Hits with energy less than this value will be ignored. + * The minimum energy required for a hit to be considered as a + * cluster center. Hits with energy less than this value will be + * ignored. */ private double seedEnergyThreshold; /** - * <b>clusterWindow</b><br/><br/> - * <code>private int <b>clusterWindow</b></code><br/><br/> - * 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. + * 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. */ private int clusterWindow; /** - * <b>hitBuffer</b><br/><br/> - * <code>private LinkedList<List<CalorimeterHit>> <b>hitBuffer</b></code><br/><br/> - * Stores a set of all the hits occurring in each clock cycle for the number - * of clock cycles that should be considered for clustering. + * Stores a set of all the hits occurring in each clock cycle for + * the number of clock cycles that should be considered for + * clustering. */ private LinkedList<Map<Long, CalorimeterHit>> hitBuffer; /** - * <b>limitClusterRange</b><br/><br/> - * <code>private boolean <b>limitClusterRange</b></code><br/><br/> * Whether an asymmetric or symmetric window should be used for * adding hits to a cluster. */ private boolean limitClusterRange = false; + /** + * Sets whether debug text should be written. + */ + private boolean verbose = false; + GTPClusterer() { - super(new String[] { "seedEnergyThreshold", "clusterWindow" }, new double[] { 0.05, 2.}); + 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")); @@ -87,10 +93,10 @@ } /** - * 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. - * + * 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. */ @@ -101,24 +107,32 @@ // Get the list of hits at the current time in the event buffer. Map<Long, CalorimeterHit> currentHits = hitBuffer.get(clusterWindow); - // DEBUG :: Print the cluster window. - System.out.printf("%n%nEvent:%n"); - int window = (hitBuffer.size() - 1) / 2; - int bufferNum = 0; - 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(currentHits.isEmpty()) { System.out.println("\tNo hits this event!"); } + // 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 @@ -128,10 +142,12 @@ // Get the actual hit object. CalorimeterHit currentHit = currentHits.get(currentID); - // DEBUG :: Print the current cluster. - System.out.printf("Cluster Check:%n"); - System.out.printf("\t(%3d, %3d) --> %.4f%n", currentHit.getIdentifierFieldValue("ix"), - currentHit.getIdentifierFieldValue("iy"), currentHit.getCorrectedEnergy(), currentHit.getRawEnergy()); + // 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(), currentHit.getRawEnergy()); + } // Store the energy of the current hit. double currentEnergy = currentHit.getRawEnergy(); @@ -139,7 +155,13 @@ // If the hit energy is lower than the minimum threshold, // then we immediately reject this hit as a possible cluster. if (currentEnergy < seedEnergyThreshold) { - System.out.printf("\tREJECT :: Does not exceed seed threshold %.4f.%n", 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; } @@ -147,6 +169,8 @@ // 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()); @@ -164,9 +188,16 @@ // is larger than then original hit. If it is, we may // stop the comparison because this is not a cluster. if (bufferHitEnergy > currentEnergy) { - 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()); + // 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; } @@ -192,9 +223,16 @@ // If it is, we may stop the comparison because this // is not a cluster. if (neighborHitEnergy > currentEnergy) { - 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()); + // 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; } @@ -214,12 +252,15 @@ // Add the cluster to the list of clusters. clusters.add(cluster); - 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()); + // 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()); + } } } @@ -228,10 +269,9 @@ } /** - * 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. - * + * 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. */ public List<Cluster> createClusters(EventHeader event, List<CalorimeterHit> hits) { @@ -253,17 +293,15 @@ } /** - * 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. - * - * @param clusterWindow - The number of additional clock cycles to include - * in the clustering checks. A negative value will be treated as zero. + * 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. + * @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. @@ -281,19 +319,17 @@ * 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. + * @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) { this.limitClusterRange = limitClusterRange; } /** - * Sets the minimum energy threshold below which hits will not be considered - * as cluster centers. - * + * Sets the minimum energy threshold below which hits will not be + * considered as cluster centers. * @param seedEnergyThreshold - The minimum energy for a cluster center. */ void setSeedEnergyThreshold(double seedEnergyThreshold) { @@ -306,7 +342,12 @@ this.seedEnergyThreshold = seedEnergyThreshold; } } - + + /** + * 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;