Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow empty input files for CollectAlignmentSummaryMetrics and FastqToSam #1859

Merged
merged 5 commits into from Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -191,12 +191,16 @@ protected void setup(final SAMFileHeader header, final File samFile) {
file.write(OUTPUT);

if (HISTOGRAM_FILE != null) {
final List<String> plotArgs = new ArrayList<>();
Collections.addAll(plotArgs, OUTPUT.getAbsolutePath(), HISTOGRAM_FILE.getAbsolutePath().replaceAll("%", "%%"), INPUT.getName());
if(file.getNumHistograms() == 0 || file.getAllHistograms().stream().allMatch(Histogram::isEmpty)) {
log.warn("No Read length histograms to plot.");
} else {
final List<String> plotArgs = new ArrayList<>();
Collections.addAll(plotArgs, OUTPUT.getAbsolutePath(), HISTOGRAM_FILE.getAbsolutePath().replaceAll("%", "%%"), INPUT.getName());

final int rResult = RExecutor.executeFromClasspath(HISTOGRAM_R_SCRIPT, plotArgs.toArray(new String[0]));
if (rResult != 0) {
throw new PicardException("R script " + HISTOGRAM_R_SCRIPT + " failed with return code " + rResult);
final int rResult = RExecutor.executeFromClasspath(HISTOGRAM_R_SCRIPT, plotArgs.toArray(new String[0]));
if (rResult != 0) {
throw new PicardException("R script " + HISTOGRAM_R_SCRIPT + " failed with return code " + rResult);
}
}
}

Expand Down
20 changes: 16 additions & 4 deletions src/main/java/picard/sam/FastqToSam.java
Expand Up @@ -234,6 +234,9 @@ public class FastqToSam extends CommandLineProgram {
@Argument(doc="Allow (and ignore) empty lines")
public Boolean ALLOW_AND_IGNORE_EMPTY_LINES = false;

@Argument(doc="Allow empty input fastq")
public Boolean ALLOW_EMPTY_FASTQ = false;

private static final SolexaQualityConverter solexaQualityConverter = SolexaQualityConverter.getSingleton();

/**
Expand Down Expand Up @@ -324,10 +327,19 @@ protected int doWork() {
final SAMFileHeader header = createSamFileHeader();
final SAMFileWriter writer = new SAMFileWriterFactory().makeWriter(header, false, OUTPUT, REFERENCE_SEQUENCE);

// Set the quality format
QUALITY_FORMAT = FastqToSam.determineQualityFormat(fileToFastqReader(FASTQ.toPath()),
(FASTQ2 == null) ? null : fileToFastqReader(FASTQ2.toPath()),
QUALITY_FORMAT);
final FastqReader reader1 = fileToFastqReader(FASTQ.toPath());
if (reader1.hasNext()) {
// Set the quality format
QUALITY_FORMAT = FastqToSam.determineQualityFormat(reader1,
(FASTQ2 == null) ? null : fileToFastqReader(FASTQ2.toPath()),
QUALITY_FORMAT);
} else {
if (ALLOW_EMPTY_FASTQ) {
LOG.warn("Input FASTQ is empty, will write out SAM/BAM file with no reads.");
} else {
throw new PicardException("Input fastq is empty. Set ALLOW_EMPTY_FASTQ if you still want to write out a file with no reads.");
}
}

// Lists for sequential files, but also used when not sequential
final List<FastqReader> readers1 = new ArrayList<>();
Expand Down
Expand Up @@ -656,14 +656,15 @@ public void testAdapterReads() throws IOException {
@DataProvider
Object[][] fileForTestReadLengthHistogram(){
return new Object[][]{
new Object[]{"summary_alignment_stats_test.sam"},
new Object[]{"summary_alignment_stats_test2.sam"},
new Object[]{"summary_alignment_stats_test3.sam"}
{"summary_alignment_stats_test.sam", true},
{"summary_alignment_stats_test2.sam", true},
{"summary_alignment_stats_test3.sam", true},
{"summary_alignment_stats_test_empty.sam", false}
};
}

@Test(dataProvider = "fileForTestReadLengthHistogram")
public void testReadLengthHistogram(final String fileToUse) throws IOException {
public void testReadLengthHistogram(final String fileToUse, final Boolean expectHistogramOut) throws IOException {
final File input = new File(TEST_DATA_DIR, fileToUse);
final File outFile = getTempOutputFile("testReadLengthHistogram", ".txt");

Expand All @@ -676,7 +677,9 @@ public void testReadLengthHistogram(final String fileToUse) throws IOException {

Assert.assertEquals(runPicardCommandLine(argsList.toArray(new String[0])),0);

Assert.assertTrue(outHist.exists());
if (expectHistogramOut) {
Assert.assertTrue(outHist.exists());
}
}


Expand Down
33 changes: 26 additions & 7 deletions src/test/java/picard/sam/FastqToSamTest.java
Expand Up @@ -165,6 +165,18 @@ public void testPairedOk(final String filename1, final String filename2, final F
convertFile(filename1, filename2, version);
}

@Test(expectedExceptionsMessageRegExp = "Input fastq is empty. Set ALLOW_EMPTY_FASTQ if you still want to write out a file with no reads.", expectedExceptions = PicardException.class)
public void testEmptyFastq() throws IOException {
final File emptyFastq = File.createTempFile("empty", ".fastq");
convertFile(emptyFastq, null, FastqQualityFormat.Illumina, false, false, false);
}

@Test
public void testEmptyFastqAllowed() throws IOException {
final File emptyFastq = File.createTempFile("empty", ".fastq");
convertFile(emptyFastq, null, FastqQualityFormat.Illumina, false, false, true);
}

private File convertFile(final String filename, final FastqQualityFormat version) throws IOException {
return convertFile(filename, null, version);
}
Expand All @@ -173,17 +185,23 @@ private File convertFile(final String fastqFilename1, final String fastqFilename
return convertFile(fastqFilename1, fastqFilename2, version,false);
}

private File convertFile(final String fastqFilename1, final String fastqFilename2, final FastqQualityFormat version,final boolean permissiveFormat) throws IOException {
private File convertFile(final String fastqFilename1, final String fastqFilename2, final FastqQualityFormat version, final boolean permissiveFormat) throws IOException {
return convertFile(fastqFilename1, fastqFilename2, version, permissiveFormat, false);
}

private File convertFile(final String fastqFilename1,
final String fastqFilename2,
final FastqQualityFormat version,
final boolean permissiveFormat,
final boolean useSequentialFastqs) throws IOException {
private File convertFile(final String fastqFilename1, final String fastqFilename2, final FastqQualityFormat version, final boolean permissiveFormat, final boolean useSequentialFastqs) throws IOException {
final File fastq1 = new File(TEST_DATA_DIR, fastqFilename1);
final File fastq2 = (fastqFilename2 != null) ? new File(TEST_DATA_DIR, fastqFilename2) : null;
return convertFile(fastq1, fastq2, version, permissiveFormat, useSequentialFastqs, false);
}

private File convertFile(final File fastq1,
final File fastq2,
final FastqQualityFormat version,
final boolean permissiveFormat,
final boolean useSequentialFastqs,
final boolean allowEmptyFastq) throws IOException {

final File samFile = newTempSamFile(fastq1.getName());

final List<String> args = new ArrayList<>();
Expand All @@ -194,9 +212,10 @@ private File convertFile(final String fastqFilename1,
args.add("READ_GROUP_NAME=rg");
args.add("SAMPLE_NAME=s1");

if (fastqFilename2 != null) args.add("FASTQ2=" + fastq2.getAbsolutePath());
if (fastq2 != null) args.add("FASTQ2=" + fastq2.getAbsolutePath());
if (permissiveFormat) args.add("ALLOW_AND_IGNORE_EMPTY_LINES=true");
if (useSequentialFastqs) args.add("USE_SEQUENTIAL_FASTQS=true");
if (allowEmptyFastq) args.add("ALLOW_EMPTY_FASTQ=true");

Assert.assertEquals(runPicardCommandLine(args), 0);
return samFile ;
Expand Down
@@ -0,0 +1,11 @@
@HD VN:1.0 SO:coordinate
@SQ SN:chr1 LN:101 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:bd01f7e11515bb6beda8f7257902aa67
@SQ SN:chr2 LN:101 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:31c33e2155b3de5e2554b693c475b310
@SQ SN:chr3 LN:101 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:631593c6dd2048ae88dcce2bd505d295
@SQ SN:chr4 LN:101 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:c60cb92f1ee5b78053c92bdbfa19abf1
@SQ SN:chr5 LN:101 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:07ebc213c7611db0eacbb1590c3e9bda
@SQ SN:chr6 LN:101 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:7be2f5e7ee39e60a6c3b5b6a41178c6d
@SQ SN:chr7 LN:404 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:da488fc432cdaf2c20c96da473a7b630
@SQ SN:chr8 LN:202 UR:file:testdata/net/sf/picard/sam/merger.fasta M5:d339678efce576d5546e88b49a487b63
@RG ID:0 SM:Hi,Momma! LB:whatever PU:me PL:ILLUMINA
@PG ID:samtools PN:samtools VN:1.12 CL:samtools view -H -o summary_alignment_stats_test_empty.sam summary_alignment_stats_test.sam