diff --git a/src/main/java/picard/illumina/CollectIlluminaLaneMetrics.java b/src/main/java/picard/illumina/CollectIlluminaLaneMetrics.java index e2b86d760..1ea0e7bad 100644 --- a/src/main/java/picard/illumina/CollectIlluminaLaneMetrics.java +++ b/src/main/java/picard/illumina/CollectIlluminaLaneMetrics.java @@ -26,23 +26,27 @@ import htsjdk.samtools.metrics.MetricBase; import htsjdk.samtools.metrics.MetricsFile; +import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.Log; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import picard.PicardException; import picard.cmdline.CommandLineProgram; import picard.cmdline.CommandLineProgramProperties; import picard.cmdline.Option; import picard.cmdline.StandardOptionDefinitions; import picard.cmdline.programgroups.Illumina; -import picard.illumina.parser.ReadStructure; -import picard.illumina.parser.Tile; -import picard.illumina.parser.TileMetricsUtil; +import picard.illumina.parser.*; import java.io.File; import java.io.FileNotFoundException; -import java.util.Collection; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; +import javax.xml.parsers.DocumentBuilderFactory; + /** * Command-line wrapper around {@link IlluminaLaneMetricsCollector}. * @author mccowan @@ -81,13 +85,36 @@ @Option(doc = "The prefix to be prepended to the file name of the output file; an appropriate suffix will be applied", shortName = StandardOptionDefinitions.OUTPUT_SHORT_NAME) public String OUTPUT_PREFIX; - @Option(doc = ReadStructure.PARAMETER_DOC, shortName = "RS") + @Option(doc = ReadStructure.PARAMETER_DOC + "\nIf not given, will use the RunInfo.xml in the run directory.", shortName = "RS", optional = true) public ReadStructure READ_STRUCTURE; @Override protected int doWork() { final MetricsFile> laneMetricsFile = this.getMetricsFile(); final MetricsFile> phasingMetricsFile = this.getMetricsFile(); + + if (READ_STRUCTURE == null) { + final File runInfo = new File(RUN_DIRECTORY + "/" + "RunInfo.xml"); + IOUtil.assertFileIsReadable(runInfo); + try { + final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(runInfo); + final NodeList reads = document.getElementsByTagName("Read"); + final List descriptors = new ArrayList<>(reads.getLength()); + for (int i = 0; i < reads.getLength(); i++) { + final Node read = reads.item(i); + final NamedNodeMap attributes = read.getAttributes(); + final int readNumber = Integer.parseInt(attributes.getNamedItem("Number").getNodeValue()); + final int numCycles = Integer.parseInt(attributes.getNamedItem("NumCycles").getNodeValue()); + final boolean isIndexedRead = attributes.getNamedItem("IsIndexedRead").getNodeValue().toUpperCase().equals("Y"); + if (readNumber != i + 1) throw new PicardException("Read number in RunInfo.xml was out of order: " + (i+1) + " != " + readNumber); + descriptors.add(new ReadDescriptor(numCycles, isIndexedRead ? ReadType.Barcode: ReadType.Template)); + } + READ_STRUCTURE = new ReadStructure(descriptors); + } catch (final Exception e) { + throw new PicardException(e.getMessage()); + } + } + IlluminaLaneMetricsCollector.collectLaneMetrics(RUN_DIRECTORY, OUTPUT_DIRECTORY, OUTPUT_PREFIX, laneMetricsFile, phasingMetricsFile, READ_STRUCTURE); return 0; } diff --git a/src/test/java/picard/illumina/IlluminaLaneMetricsCollectorTest.java b/src/test/java/picard/illumina/IlluminaLaneMetricsCollectorTest.java index 59c90f682..4cb9880f5 100644 --- a/src/test/java/picard/illumina/IlluminaLaneMetricsCollectorTest.java +++ b/src/test/java/picard/illumina/IlluminaLaneMetricsCollectorTest.java @@ -8,6 +8,7 @@ import org.testng.annotations.Test; import java.io.File;import java.lang.Exception;import java.lang.Object;import java.lang.String; +import java.util.Arrays; /** @author mccowan */ public class IlluminaLaneMetricsCollectorTest { @@ -20,19 +21,21 @@ private static File buildOutputFile(final File directory, final String prefix, f @Test(dataProvider = "testLaneMetrics") public void testWriteLaneMetrics(final String testRun) throws Exception { - final CollectIlluminaLaneMetrics clp = new CollectIlluminaLaneMetrics(); - clp.OUTPUT_DIRECTORY = IOUtil.createTempDir("illuminaLaneMetricsCollectorTest", null); - clp.RUN_DIRECTORY = new File(TEST_DIRECTORY, testRun); - clp.OUTPUT_PREFIX = "test"; - clp.READ_STRUCTURE = new ReadStructure("101T8B101T"); - clp.doWork(); + for (final boolean useReadStructure : Arrays.asList(true, false)) { + final CollectIlluminaLaneMetrics clp = new CollectIlluminaLaneMetrics(); + clp.OUTPUT_DIRECTORY = IOUtil.createTempDir("illuminaLaneMetricsCollectorTest", null); + clp.RUN_DIRECTORY = new File(TEST_DIRECTORY, testRun); + clp.OUTPUT_PREFIX = "test"; + if (useReadStructure) clp.READ_STRUCTURE = new ReadStructure("101T8B101T"); + clp.doWork(); - final File laneMetricsFile = buildOutputFile(clp.OUTPUT_DIRECTORY, clp.OUTPUT_PREFIX, IlluminaLaneMetrics.getExtension()); - final File canonicalOutputFile = buildOutputFile(TEST_DIRECTORY, testRun, IlluminaLaneMetrics.getExtension()); + final File laneMetricsFile = buildOutputFile(clp.OUTPUT_DIRECTORY, clp.OUTPUT_PREFIX, IlluminaLaneMetrics.getExtension()); + final File canonicalOutputFile = buildOutputFile(TEST_DIRECTORY, testRun, IlluminaLaneMetrics.getExtension()); - IOUtil.assertFilesEqual(canonicalOutputFile, laneMetricsFile); + IOUtil.assertFilesEqual(canonicalOutputFile, laneMetricsFile); - IOUtil.deleteDirectoryTree(clp.OUTPUT_DIRECTORY); + IOUtil.deleteDirectoryTree(clp.OUTPUT_DIRECTORY); + } } @DataProvider(name = "testLaneMetrics") @@ -46,22 +49,24 @@ public void testWriteLaneMetrics(final String testRun) throws Exception { @Test(dataProvider = "testCollectIlluminaLaneMetrics") public void testCollectIlluminaLaneMetrics(final String testRun, final ReadStructure readStructure) throws Exception { - final File runDirectory = new File(TILE_RUN_DIRECTORY, testRun); - final CollectIlluminaLaneMetrics clp = new CollectIlluminaLaneMetrics(); - clp.OUTPUT_DIRECTORY = IOUtil.createTempDir("illuminaLaneMetricsCollectorTest", null); - clp.RUN_DIRECTORY = runDirectory; - clp.OUTPUT_PREFIX = "test"; - clp.READ_STRUCTURE = readStructure; - clp.doWork(); + for (final boolean useReadStructure : Arrays.asList(true, false)) { + final File runDirectory = new File(TILE_RUN_DIRECTORY, testRun); + final CollectIlluminaLaneMetrics clp = new CollectIlluminaLaneMetrics(); + clp.OUTPUT_DIRECTORY = IOUtil.createTempDir("illuminaLaneMetricsCollectorTest", null); + clp.RUN_DIRECTORY = runDirectory; + clp.OUTPUT_PREFIX = "test"; + if (useReadStructure) clp.READ_STRUCTURE = readStructure; + clp.doWork(); - final File phasingMetricsPhile = buildOutputFile(clp.OUTPUT_DIRECTORY, clp.OUTPUT_PREFIX, IlluminaPhasingMetrics.getExtension()); - final File canonicalPhasingPhile = buildOutputFile(runDirectory, testRun, IlluminaPhasingMetrics.getExtension()); - IOUtil.assertFilesEqual(canonicalPhasingPhile, phasingMetricsPhile); + final File phasingMetricsPhile = buildOutputFile(clp.OUTPUT_DIRECTORY, clp.OUTPUT_PREFIX, IlluminaPhasingMetrics.getExtension()); + final File canonicalPhasingPhile = buildOutputFile(runDirectory, testRun, IlluminaPhasingMetrics.getExtension()); + IOUtil.assertFilesEqual(canonicalPhasingPhile, phasingMetricsPhile); - final File laneMetricsFile = buildOutputFile(clp.OUTPUT_DIRECTORY, clp.OUTPUT_PREFIX, IlluminaLaneMetrics.getExtension()); - final File canonicalLaneFile = buildOutputFile(runDirectory, testRun, IlluminaLaneMetrics.getExtension()); - IOUtil.assertFilesEqual(canonicalLaneFile, laneMetricsFile); - IOUtil.deleteDirectoryTree(clp.OUTPUT_DIRECTORY); + final File laneMetricsFile = buildOutputFile(clp.OUTPUT_DIRECTORY, clp.OUTPUT_PREFIX, IlluminaLaneMetrics.getExtension()); + final File canonicalLaneFile = buildOutputFile(runDirectory, testRun, IlluminaLaneMetrics.getExtension()); + IOUtil.assertFilesEqual(canonicalLaneFile, laneMetricsFile); + IOUtil.deleteDirectoryTree(clp.OUTPUT_DIRECTORY); + } } @DataProvider(name = "testCollectIlluminaLaneMetrics") diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130318_SL-HBB_0226_BFCC1WYMACXX/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130318_SL-HBB_0226_BFCC1WYMACXX/RunInfo.xml new file mode 100644 index 000000000..115c688e3 --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130318_SL-HBB_0226_BFCC1WYMACXX/RunInfo.xml @@ -0,0 +1,13 @@ + + + + BFCC1WYMACXX + SL-HBB + 130318 + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130321_SL-MAK_0035_FC000000000-A306B/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130321_SL-MAK_0035_FC000000000-A306B/RunInfo.xml new file mode 100644 index 000000000..a460e873d --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130321_SL-MAK_0035_FC000000000-A306B/RunInfo.xml @@ -0,0 +1,13 @@ + + + + FC000000000-A306B + SL-MAK + 130321 + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130401_SL-HAC_0022_BH07PBADXX/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130401_SL-HAC_0022_BH07PBADXX/RunInfo.xml new file mode 100644 index 000000000..6150ba2bc --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/130401_SL-HAC_0022_BH07PBADXX/RunInfo.xml @@ -0,0 +1,13 @@ + + + + BH07PBADXX + SL-HAC + 130401 + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/A67HY/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/A67HY/RunInfo.xml new file mode 100644 index 000000000..73a249143 --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/A67HY/RunInfo.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/A7LE0/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/A7LE0/RunInfo.xml new file mode 100644 index 000000000..1c50f30d5 --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/A7LE0/RunInfo.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/C2MFAACXX/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/C2MFAACXX/RunInfo.xml new file mode 100644 index 000000000..937a0bbac --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/C2MFAACXX/RunInfo.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/H7BATADXX/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/H7BATADXX/RunInfo.xml new file mode 100644 index 000000000..d42c0f3b1 --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/H7BATADXX/RunInfo.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/H7H7RADXX/RunInfo.xml b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/H7H7RADXX/RunInfo.xml new file mode 100644 index 000000000..1b3ac9ce3 --- /dev/null +++ b/testdata/picard/illumina/IlluminaLaneMetricsCollectorTest/tileRuns/H7H7RADXX/RunInfo.xml @@ -0,0 +1,11 @@ + + + + + + + + + + +