Author: [log in to unmask] Date: Wed Feb 4 14:03:29 2015 New Revision: 2042 Log: Copy hit list so that modifications by Clusterer does not effect master list. Add optional validation of output clusters. Setup logger for specific Driver class. HPSJAVA-412 Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java Modified: java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java ============================================================================= --- java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java (original) +++ java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java Wed Feb 4 14:03:29 2015 @@ -1,5 +1,6 @@ package org.hps.recon.ecal.cluster; +import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; @@ -31,9 +32,9 @@ */ public class ClusterDriver extends Driver { - protected static Logger logger = LogUtil.create(ClusterDriver.class, new BasicFormatter(ClusterDriver.class.getSimpleName())); - - protected String ecalName = "Ecal"; + Logger logger; + + protected String ecalName = "Ecal"; protected HPSEcal3 ecal; protected NeighborMap neighborMap; protected String outputClusterCollectionName = "EcalClusters"; @@ -49,11 +50,13 @@ protected boolean calculateProperties = false; protected boolean applyCorrections = false; protected boolean sortHits = false; + protected boolean validateClusters = false; /** * No argument constructor. */ public ClusterDriver() { + logger = LogUtil.create(getClass().getSimpleName(), new BasicFormatter(getClass().getSimpleName())); } /** @@ -177,6 +180,14 @@ */ public void setCuts(double[] cuts) { this.cuts = cuts; + } + + /** + * Set whether to validate the output. + * @param validateClusters True to validate output. + */ + public void setValidateClusters(boolean validateClusters) { + this.validateClusters = validateClusters; } /** @@ -222,7 +233,10 @@ if (event.hasCollection(CalorimeterHit.class, inputHitCollectionName)) { List<CalorimeterHit> hits = event.get(CalorimeterHit.class, inputHitCollectionName); logger.fine("input hit collection " + inputHitCollectionName + " has " + hits.size() + " hits"); - List<Cluster> clusters = clusterer.createClusters(event, hits); + + // Cluster the hits, copying the list from the event in case the clustering algorithm modifies it. + List<Cluster> clusters = clusterer.createClusters(event, new ArrayList<CalorimeterHit>(hits)); + if (clusters == null) { throw new RuntimeException("The clusterer returned a null list from its createClusters method."); } @@ -258,6 +272,11 @@ logger.finer("Collection is set to transient and will not be persisted."); event.getMetaData(clusters).setTransient(true); } + + if (validateClusters) { + // Perform basic validation checks. + this.validateClusters(event); + } } } else { this.getLogger().severe("The input hit collection " + this.inputHitCollectionName + " is missing from the event."); @@ -277,7 +296,7 @@ } /** - * Get a Clusterer using type inference for the concrete type. + * Get a {@link Clusterer} using type inference for the concrete type. * @return The Clusterer object. */ @SuppressWarnings("unchecked") @@ -285,4 +304,51 @@ // Return the Clusterer and cast it to the type provided by the caller. return (ClustererType) clusterer; } -} + + /** + * Perform basic validation of the cluster output collection, including checking + * that the cluster collection was created, clusters are not null, + * none of the clustered hits are null, and each hit exists in the input + * hit collection. + * @param event The LCSim event. + */ + void validateClusters(EventHeader event) { + if (!event.hasCollection(Cluster.class, outputClusterCollectionName)) { + throw new RuntimeException("Cluster collection " + outputClusterCollectionName + " is missing."); + } + List<Cluster> clusters = event.get(Cluster.class, outputClusterCollectionName); + List<CalorimeterHit> inputHitCollection = event.get(CalorimeterHit.class, inputHitCollectionName); + for (int clusterIndex = 0; clusterIndex < clusters.size(); clusterIndex++) { + logger.finest("checking cluster " + clusterIndex); + Cluster cluster = clusters.get(clusterIndex); + if (clusters.get(clusterIndex) == null) { + throw new RuntimeException("The Cluster at index " + clusterIndex + " is null."); + } + List<CalorimeterHit> clusterHits = cluster.getCalorimeterHits(); + logger.finest("cluster has " + clusterHits.size() + " hits"); + for (int hitIndex = 0; hitIndex < clusterHits.size(); hitIndex++) { + logger.finest("checking cluster hit " + hitIndex); + CalorimeterHit clusterHit = clusterHits.get(hitIndex); + if (clusterHit == null) { + throw new RuntimeException("The CalorimeterHit at index " + hitIndex + " in the cluster is null."); + } + if (!inputHitCollection.contains(clusterHit)) { + logger.severe("The CalorimeterHit at index " + hitIndex + " with ID " + clusterHit.getIdentifier().toHexString() + " is missing from the input hit collection."); + printHitIDs(inputHitCollection); + throw new RuntimeException("The CalorimeterHit at index " + hitIndex + " in the cluster is missing from the input hit collection."); + } + } + } + } + + void printHitIDs(List<CalorimeterHit> hits) { + StringBuffer buffer = new StringBuffer(); + buffer.append("hit IDs"); + buffer.append('\n'); + for (CalorimeterHit hit : hits) { + buffer.append(hit.getIdentifier().toHexString()); + buffer.append('\n'); + } + logger.finest(buffer.toString()); + } +}