Author: [log in to unmask] Date: Thu Feb 19 17:54:39 2015 New Revision: 2172 Log: Improvements to ClustererTest including reading back and checking the validity of the output LCIO file. Modified: java/trunk/ecal-recon/src/test/java/org/hps/recon/ecal/cluster/ClustererTest.java Modified: java/trunk/ecal-recon/src/test/java/org/hps/recon/ecal/cluster/ClustererTest.java ============================================================================= --- java/trunk/ecal-recon/src/test/java/org/hps/recon/ecal/cluster/ClustererTest.java (original) +++ java/trunk/ecal-recon/src/test/java/org/hps/recon/ecal/cluster/ClustererTest.java Thu Feb 19 17:54:39 2015 @@ -33,81 +33,93 @@ import org.lcsim.util.test.TestUtil.TestOutputFile; /** - * This test does basic sanity checks on the output from the {@link Clusterer} algorithms, - * and it creates an AIDA file with some useful plots, as well as optionally writes - * an LCIO file with the event data plus the clusters. + * This test performs basic sanity checks on the output from the various clustering algorithms, + * and it creates an AIDA file with some useful plots, as well as optionally writes an LCIO + * file with the event data plus the clusters. * * @author Jeremy McCormick <[log in to unmask]> + * + * @see Clusterer + * @see org.lcsim.event.Cluster + * @see org.lcsim.event.CalorimeterHit */ public class ClustererTest extends TestCase { - + static int nEvents = 100; static final String fileLocation = "http://www.lcsim.org/test/hps-java/MockDataReconTest.slcio"; File inputFile; File testOutputDir; - - static class ClustererTestSetup { - + + static class ClustererTestConfig { + boolean writeLcioFile; boolean checkSeedHit; - boolean applyCorrections; boolean checkHitEnergy; boolean checkPropCalc; boolean checkClusterPosition; - boolean checkHitPositions; - boolean calculateProperties; - boolean sortHits; + boolean checkNullHits; + boolean checkHitPositions; double[] cuts = null; - ClusterType clusterType; + ClusterType clusterType; + String clustererName; + + ClustererTestConfig(String clustererName, double[] cuts) { + this.clustererName = clustererName; + this.cuts = cuts; + } + + ClustererTestConfig(String clustererName) { + this.clustererName = clustererName; + } + + ClustererTestConfig() { + } + + ClustererTestConfig writeLcioFile() { + writeLcioFile = true; + return this; + } + + ClustererTestConfig checkSeedHit() { + checkSeedHit = true; + return this; + } + + ClustererTestConfig checkHitEnergy() { + checkHitEnergy = true; + return this; + } + + ClustererTestConfig checkPropCalc() { + checkPropCalc = true; + return this; + } + + ClustererTestConfig checkClusterType(ClusterType clusterType) { + this.clusterType = clusterType; + return this; + } + + ClustererTestConfig checkClusterPosition() { + this.checkClusterPosition = true; + return this; + } + + ClustererTestConfig checkHitPositions() { + this.checkHitPositions = true; + return this; + } - ClustererTestSetup(double[] cuts) { - this.cuts = cuts; - } - - ClustererTestSetup() { - } - - ClustererTestSetup writeLcioFile() { - writeLcioFile = true; - return this; - } - - ClustererTestSetup checkSeedHit() { - checkSeedHit = true; - return this; - } - - ClustererTestSetup sortHits() { - sortHits = true; - return this; - } - - ClustererTestSetup checkHitEnergy() { - checkHitEnergy = true; - return this; - } - - ClustererTestSetup checkPropCalc() { - checkPropCalc = true; - return this; - } - - ClustererTestSetup checkClusterType(ClusterType clusterType) { - this.clusterType = clusterType; - return this; - } - - ClustererTestSetup checkPosition() { - this.checkClusterPosition = true; - return this; - } - - ClustererTestSetup checkHitPositions() { - this.checkHitPositions = true; - return this; - } - } - + ClustererTestConfig checkNullHits() { + this.checkNullHits = true; + return this; + } + + String getClusterCollectionName() { + return clustererName + "Clusters"; + } + } + public void setUp() { // Cache the input file. try { @@ -115,172 +127,249 @@ } catch (IOException e) { throw new RuntimeException(e); } - + // Create test output directory. testOutputDir = new TestOutputFile(getClass().getSimpleName()); - testOutputDir.mkdir(); - + testOutputDir.mkdir(); + // Initialize the conditions system. new DatabaseConditionsManager(); DatabaseConditionsManager.getInstance().setLogLevel(Level.WARNING); } - + /** * Test the recon clustering algorithm, formerly called the IC clusterer. */ - public void testReconClusterer() { - runClustererTest("ReconClusterer", - new ClustererTestSetup() - .writeLcioFile() - .checkSeedHit() - .checkClusterType(ClusterType.RECON) - .checkHitEnergy() - .checkPosition() - .checkHitPositions()); - } - + public void testReconClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("ReconClusterer") + .writeLcioFile() + .checkSeedHit() + .checkClusterType(ClusterType.RECON) + .checkHitEnergy() + .checkClusterPosition() + .checkNullHits() + .checkHitPositions()); + } + /** * Test a simple version of the recon clustering. */ - public void testSimpleReconClusterer() { - runClustererTest("SimpleReconClusterer", - new ClustererTestSetup() - .writeLcioFile() - .checkSeedHit() - .checkClusterType(ClusterType.SIMPLE_RECON) - .checkHitEnergy() - .checkPosition()); - } - + public void testSimpleReconClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("SimpleReconClusterer") + .writeLcioFile() + .checkSeedHit() + .checkClusterType(ClusterType.SIMPLE_RECON) + .checkHitEnergy() + .checkClusterPosition() + .checkNullHits() + .checkHitPositions()); + } + /** * Test a simplistic NN clustering algorithm. */ - public void testNearestNeighborClusterer() { - runClustererTest("NearestNeighborClusterer", - new ClustererTestSetup(new double[] { 0.0075, 3 }) - .writeLcioFile() - .checkClusterType(ClusterType.NN) - .checkHitEnergy() - .checkPosition()); - } - + public void testNearestNeighborClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("NearestNeighborClusterer", new double[] { 0.0075, 3 }) + .writeLcioFile() + .checkClusterType(ClusterType.NN) + .checkHitEnergy() + .checkClusterPosition() + .checkHitPositions() + .checkNullHits()); + } + /** * Test the clustering algorithm from the Test Run proposal document. */ - public void testLegacyClusterer() { - runClustererTest("LegacyClusterer", - new ClustererTestSetup() - .writeLcioFile() - .checkClusterType(ClusterType.LEGACY) - .checkHitEnergy() - .checkPosition()); - } - + public void testLegacyClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("LegacyClusterer") + .writeLcioFile() + .checkClusterType(ClusterType.LEGACY) + .checkHitEnergy() + .checkClusterPosition() + .checkHitPositions() + .checkNullHits()); + } + /** * Test the online version of the GTP algorithm. */ - public void testGTPOnlineClusterer() { - runClustererTest("GTPOnlineClusterer", - new ClustererTestSetup() - .writeLcioFile().checkSeedHit() - .checkClusterType(ClusterType.GTP_ONLINE) - .checkHitEnergy() - .checkPosition()); - } - + public void testGTPOnlineClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("GTPOnlineClusterer") + .writeLcioFile() + .checkSeedHit() + .checkClusterType(ClusterType.GTP_ONLINE) + .checkHitEnergy() + .checkClusterPosition() + .checkHitPositions() + .checkNullHits()); + } + /** * Test the CTP clustering algorithm. - */ - public void testCTPClusterer() { - runClustererTest("CTPClusterer", - new ClustererTestSetup() - .writeLcioFile() - .checkClusterType(ClusterType.CTP) - .checkPosition()); - } - + */ + public void testCTPClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("CTPClusterer") + .writeLcioFile() + .checkClusterType(ClusterType.CTP) + .checkClusterPosition()); + } + /** * Test the GTP clustering algorithm. */ - public void testGTPClusterer() { - runClustererTest("GTPClusterer", - new ClustererTestSetup() - .writeLcioFile() - .checkClusterType(ClusterType.GTP) - .checkHitEnergy() - .checkPosition()); - } - + public void testGTPClusterer() throws Exception { + runClustererTest(new ClustererTestConfig("GTPClusterer") + .writeLcioFile() + .checkClusterType(ClusterType.GTP) + .checkClusterPosition()); + } + /** * Run the standard test for a Clusterer. * @param clustererName The name of the Clusterer. * @param cuts The cut values. * @param writeLcioFile Whether or not to write an LCIO output file. */ - private void runClustererTest(String clustererName, ClustererTestSetup setup) { - - System.out.println("testing Clusterer " + clustererName + " ..."); - + private void runClustererTest(ClustererTestConfig config) throws Exception { + + /********************************************************** + * Run the job to create clusters and write to LCIO file. * + **********************************************************/ + System.out.println("testing Clusterer " + config.clustererName + " ..."); // Configure the loop. - LCSimLoop loop = new LCSimLoop(); + LCSimLoop loop = new LCSimLoop(); try { // Set the input LCIO file. loop.setLCIORecordSource(inputFile); } catch (IOException e) { throw new RuntimeException(e); - } - + } + // Setup event number print outs. EventMarkerDriver eventMarkerDriver = new EventMarkerDriver(); eventMarkerDriver.setEventInterval(1); loop.add(eventMarkerDriver); + + // Configure the ClusterDriver and add it to the loop. + ClusterDriver clusterDriver = new ClusterDriver(); + clusterDriver.setClustererName(config.clustererName); + if (config.cuts != null) { + clusterDriver.setCuts(config.cuts); + } + clusterDriver.getLogger().setLevel(Level.ALL); + clusterDriver.setInputHitCollectionName("EcalHits"); + clusterDriver.setOutputClusterCollectionName(config.getClusterCollectionName()); + clusterDriver.setRaiseErrorNoHitCollection(true); + loop.add(clusterDriver); + + // This Driver checks the Clusters for validity. + loop.add(new ClusterCheckDriver(config)); - // Configure the ClusterDriver and add it to the loop. - String clusterCollectionName = clustererName + "Clusters"; - ClusterDriver clusterDriver = new ClusterDriver(); - clusterDriver.setClustererName(clustererName); - if (setup.cuts != null) { - clusterDriver.setCuts(setup.cuts); - } - clusterDriver.getLogger().setLevel(Level.ALL); - clusterDriver.setInputHitCollectionName("EcalHits"); - clusterDriver.setOutputClusterCollectionName(clusterCollectionName); - clusterDriver.setRaiseErrorNoHitCollection(true); - clusterDriver.setSortHits(setup.sortHits); - loop.add(clusterDriver); + // This Driver makes plots from the Cluster data. + loop.add(new ClusterPlotsDriver(config)); + + // Setup writing of LCIO file with the output Clusters from this clustering algorithm. + String outputFilePath = testOutputDir.getPath() + File.separator + config.clustererName + ".slcio"; + if (config.writeLcioFile) { + loop.add(new LCIODriver(outputFilePath)); + } - // This Driver generates plots and the output LCIO file. - loop.add(new ClusterCheckDriver(clusterCollectionName, setup)); - - if (setup.writeLcioFile) { - loop.add(new LCIODriver(testOutputDir.getPath() + File.separator + clustererName + ".slcio")); - } - - // Run the job. - long startMillis = System.currentTimeMillis(); - try { - loop.loop(nEvents); - long elapsedSeconds = (System.currentTimeMillis() - startMillis) / 1000; - System.out.println(clustererName + " took " + elapsedSeconds + "s for " + - loop.getTotalSupplied() + " events which is " + (double)loop.getTotalSupplied()/(double)elapsedSeconds + - " events/s"); - } catch (IOException e) { - throw new RuntimeException(e); - } + // Run job over the input events to generate clusters, check their validity, and fill plots. + long startNanos = System.nanoTime(); + loop.loop(nEvents); + long elapsedMillis = (System.nanoTime() - startNanos) / 1000000; + System.out.println(config.clustererName + " took " + elapsedMillis + "ms for " + loop.getTotalSupplied() + + " events which is " + (double) loop.getTotalSupplied() / (((double) elapsedMillis) / 1000.) + " events/s"); loop.dispose(); - } - - /** - * This Driver will check some of the basic Cluster values (currently just size and energy). - * It also produces some QA plots for each Clusterer in its own output AIDA dir within the plot tree. - */ - static class ClusterCheckDriver extends Driver { - + + /*************************************************** + * Reread the file and run the check Driver again. * + ***************************************************/ + File clusterFile = new File(testOutputDir.getPath() + File.separator + config.clustererName + ".slcio"); + System.out.println("rereading " + clusterFile.getPath() + "..."); + loop = new LCSimLoop(); + loop.setLCIORecordSource(clusterFile); + loop.add(new ClusterCheckDriver(config)); + loop.loop(nEvents); + loop.dispose(); + + } + + /** + * Driver that performs test assertions on Cluster collections. + */ + static class ClusterCheckDriver extends Driver { + + ClustererTestConfig config; + + ClusterCheckDriver(ClustererTestConfig config) { + this.config = config; + } + + public void process(EventHeader event) { + List<Cluster> clusters = event.get(Cluster.class, config.getClusterCollectionName()); + for (Cluster cluster : clusters) { + // Test assertions. + checkCluster(cluster); + } + } + + /** + * @param cluster + */ + private void checkCluster(Cluster cluster) { + assertTrue("The cluster energy is invalid.", cluster.getEnergy() > 0.); + assertTrue("The cluster has no hits.", !cluster.getCalorimeterHits().isEmpty()); + if (config.checkSeedHit) { + assertEquals("First hit is not seed.", cluster.getCalorimeterHits().get(0), ClusterUtilities.findHighestEnergyHit(cluster)); + } + if (config.checkPropCalc) { + assertTrue("Cluster properties not calculated.", !((BaseCluster) cluster).needsPropertyCalculation()); + } + if (config.clusterType != null) { + assertEquals("Cluster type is not correct.", config.clusterType, ClusterType.getClusterType(cluster.getType())); + } + if (config.checkClusterPosition) { + double[] position = cluster.getPosition(); + assertTrue("Position X is invalid.", Math.abs(position[0]) < 400. && position[0] != 0.); + assertTrue("Position Y is invalid.", Math.abs(position[1]) > 25. && Math.abs(position[1]) < 90.); + assertTrue("Position Z is invalid.", position[2] > 1385. && position[2] < 1480.); + } + for (CalorimeterHit hit : cluster.getCalorimeterHits()) { + if (config.checkNullHits) { + TestCase.assertNotNull("A hit from the cluster points to null.", hit); + } + if (hit != null) { + if (config.checkHitPositions) { + double[] hitPosition = hit.getPosition(); + assertTrue("Hit Position X is invalid.", hitPosition[0] != 0.); + assertTrue("Hit Position Y is invalid.", hitPosition[1] != 0.); + assertTrue("Hit Position Z is invalid.", hitPosition[2] != 0.); + EcalCrystal crystal = CalorimeterHitUtilities.findCrystal(hit); + assertTrue("Hit does not link correctly to geometry.", crystal != null); + } + if (config.checkHitEnergy) { + assertTrue("Hit energy " + hit.getCorrectedEnergy() + " is <= 0.", hit.getCorrectedEnergy() > 0.); + } + double time = hit.getTime(); + assertTrue("Hit time is invalid.", time != 0.); + } + } + } + } + + /** + * This Driver produces some QA plots for each Clusterer in its own output AIDA dir within the plot tree. + * All the plots are written to a single file at the end of the job. + */ + static class ClusterPlotsDriver extends Driver { + AIDA aida = AIDA.defaultInstance(); IHistogram1D energyH1D; IHistogram1D uncorrectedEnergyH1D; IHistogram1D countH1D; - IHistogram1D sizeH1D; + IHistogram1D sizeH1D; IHistogram1D highestHitEnergyH1D; IHistogram1D hitEnergyH1D; IHistogram2D rawVsCorrectedH2D; @@ -303,14 +392,14 @@ IHistogram1D latestHitTimeH1D; String clusterCollectionName; String clustererName; - - ClustererTestSetup setup; - - ClusterCheckDriver(String clusterCollectionName, ClustererTestSetup setup) { - this.clusterCollectionName = clusterCollectionName; - this.setup = setup; - } - + + ClustererTestConfig config; + + ClusterPlotsDriver(ClustererTestConfig config) { + this.config = config; + this.clusterCollectionName = config.getClusterCollectionName(); + } + public void startOfData() { energyH1D = aida.histogram1D(clusterCollectionName + "/Cluster Energy", 300, 0.0, 3.0); uncorrectedEnergyH1D = aida.histogram1D(clusterCollectionName + "/Uncorrected Cluster Energy", 200, 0.0, 2.0); @@ -337,17 +426,14 @@ latestHitTimeH1D = aida.histogram1D(clusterCollectionName + "/Latest Hit Time", 500, 0., 500.); clusterVsHitCountC2d = aida.cloud2D(clusterCollectionName + "/Cluster Vs Hit Count"); } - + public void process(EventHeader event) { List<Cluster> clusters = event.get(Cluster.class, this.clusterCollectionName); for (Cluster cluster : clusters) { - - // Test assertions. - checkCluster(cluster); - + // Fill plots. fillClusterPlots(cluster); - } + } countH1D.fill(clusters.size()); clusterVsHitCountC2d.fill(clusters.size(), ClusterUtilities.getHits(clusters).size()); } @@ -363,7 +449,7 @@ rawVsCorrectedH2D.fill(rawEnergy, cluster.getEnergy()); for (CalorimeterHit hit : cluster.getCalorimeterHits()) { hitEnergyH1D.fill(hit.getCorrectedEnergy()); - } + } highestHitEnergyH1D.fill(ClusterUtilities.findHighestEnergyHit(cluster).getCorrectedEnergy()); positionXH1D.fill(Math.abs(cluster.getPosition()[0])); positionYH1D.fill(Math.abs(cluster.getPosition()[1])); @@ -374,11 +460,11 @@ shapeParam3H1D.fill(cluster.getShape()[2]); } iphiC1D.fill(Math.toDegrees(cluster.getIPhi())); - ithetaC1D.fill(Math.toDegrees(cluster.getITheta())); + ithetaC1D.fill(Math.toDegrees(cluster.getITheta())); clusterPositionC2D.fill(cluster.getPosition()[0], cluster.getPosition()[1]); - - //Map<MCParticle, List<SimCalorimeterHit>> particleHitMap = ClusterUtilities.createParticleHitMap(cluster); - + + // Map<MCParticle, List<SimCalorimeterHit>> particleHitMap = ClusterUtilities.createParticleHitMap(cluster); + Set<MCParticle> particles = ClusterUtilities.findMCParticles(cluster); double particleEnergy = 0; double highestParticleEnergy = Double.MIN_VALUE; @@ -400,46 +486,8 @@ earliestHitTimeH1D.fill(hitsForTime.get(0).getTime()); latestHitTimeH1D.fill(hitsForTime.get(hitsForTime.size() - 1).getTime()); } - - /** - * @param cluster - */ - private void checkCluster(Cluster cluster) { - assertTrue("The cluster energy is invalid.", cluster.getEnergy() > 0.); - assertTrue("The cluster has no hits.", !cluster.getCalorimeterHits().isEmpty()); - if (setup.checkSeedHit) { - assertEquals("First hit is not seed.", cluster.getCalorimeterHits().get(0), ClusterUtilities.findHighestEnergyHit(cluster)); - } - if (setup.checkPropCalc) { - assertTrue("Cluster properties not calculated.", !((BaseCluster)cluster).needsPropertyCalculation()); - } - if (setup.clusterType != null) { - assertEquals("Cluster type is not correct.", setup.clusterType, ClusterType.getClusterType(cluster.getType())); - } - if (setup.checkHitEnergy) { - for (CalorimeterHit hit : cluster.getCalorimeterHits()) { - assertTrue("Hit energy " + hit.getCorrectedEnergy() + " is <= 0.", hit.getCorrectedEnergy() > 0.); - } - } - if (setup.checkClusterPosition) { - double[] position = cluster.getPosition(); - assertTrue("Position X is invalid.", Math.abs(position[0]) < 400. && position[0] != 0.); - assertTrue("Position Y is invalid.", Math.abs(position[1]) > 25. && Math.abs(position[1]) < 90.); - assertTrue("Position Z is invalid.", position[2] > 1385. && position[2] < 1480.); - } - if (setup.checkHitPositions) { - for (CalorimeterHit hit : cluster.getCalorimeterHits()) { - double[] hitPosition = hit.getPosition(); - assertTrue("Hit Position X is invalid.", hitPosition[0] != 0.); - assertTrue("Hit Position Y is invalid.", hitPosition[1] != 0.); - assertTrue("Hit Position Z is invalid.", hitPosition[2] != 0.); - EcalCrystal crystal = CalorimeterHitUtilities.findCrystal(hit); - assertTrue("Hit does not link correctly to geometry.", crystal != null); - } - } - } - } - + } + /** * This method writes the AIDA file to disk from all the tests. */ @@ -449,5 +497,5 @@ } catch (IOException e) { throw new RuntimeException(e); } - } + } }