diff --git a/public/java/src/org/broadinstitute/sting/gatk/iterators/LocusIteratorByState.java b/public/java/src/org/broadinstitute/sting/gatk/iterators/LocusIteratorByState.java index f97069189..b5d5dfc0e 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/iterators/LocusIteratorByState.java +++ b/public/java/src/org/broadinstitute/sting/gatk/iterators/LocusIteratorByState.java @@ -301,6 +301,7 @@ public class LocusIteratorByState extends LocusIterator { final CigarOperator op = state.getCurrentCigarOperator(); // current cigar operator final CigarElement nextElement = state.peekForwardOnGenome(); // next cigar element final CigarElement lastElement = state.peekBackwardOnGenome(); // last cigar element + final boolean isSingleElementCigar = nextElement == lastElement; final CigarOperator nextOp = nextElement.getOperator(); // next cigar operator final CigarOperator lastOp = lastElement.getOperator(); // last cigar operator final int readOffset = state.getReadOffset(); // the base offset on this read @@ -308,7 +309,7 @@ public class LocusIteratorByState extends LocusIterator { final boolean isBeforeDeletion = nextOp == CigarOperator.DELETION; final boolean isAfterDeletion = lastOp == CigarOperator.DELETION; final boolean isBeforeInsertion = nextOp == CigarOperator.INSERTION; - final boolean isAfterInsertion = lastOp == CigarOperator.INSERTION; + final boolean isAfterInsertion = lastOp == CigarOperator.INSERTION && !isSingleElementCigar; final boolean isNextToSoftClip = nextOp == CigarOperator.S || (state.getGenomeOffset() == 0 && read.getSoftStart() != read.getAlignmentStart()); int nextElementLength = nextElement.getLength(); @@ -328,8 +329,10 @@ public class LocusIteratorByState extends LocusIterator { else { if (!filterBaseInRead(read, location.getStart())) { String insertedBaseString = null; - if (nextOp == CigarOperator.I) - insertedBaseString = new String(Arrays.copyOfRange(read.getReadBases(), readOffset + 1, readOffset + 1 + nextElement.getLength())); + if (nextOp == CigarOperator.I) { + final int insertionOffset = isSingleElementCigar ? 0 : 1; + insertedBaseString = new String(Arrays.copyOfRange(read.getReadBases(), readOffset + insertionOffset, readOffset + insertionOffset + nextElement.getLength())); + } pile.add(new PileupElement(read, readOffset, false, isBeforeDeletion, isAfterDeletion, isBeforeInsertion, isAfterInsertion, isNextToSoftClip, insertedBaseString, nextElementLength)); size++; diff --git a/public/java/test/org/broadinstitute/sting/gatk/iterators/LocusIteratorByStateUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/iterators/LocusIteratorByStateUnitTest.java index dc908c323..e65a7fb27 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/iterators/LocusIteratorByStateUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/iterators/LocusIteratorByStateUnitTest.java @@ -104,7 +104,7 @@ public class LocusIteratorByStateUnitTest extends BaseTest { after.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20}); after.setCigarString("10M"); - List reads = Arrays.asList(before,during,after); + List reads = Arrays.asList(before, during, after); // create the iterator by state with the fake reads and fake records li = makeLTBS(reads,readAttributes); @@ -134,9 +134,9 @@ public class LocusIteratorByStateUnitTest extends BaseTest { // create a test version of the Reads object ReadProperties readAttributes = createTestReadProperties(); - SAMRecord indelOnlyRead = ArtificialSAMUtils.createArtificialRead(header,"indelOnly",0,firstLocus,76); + SAMRecord indelOnlyRead = ArtificialSAMUtils.createArtificialRead(header, "indelOnly", 0, firstLocus, 76); indelOnlyRead.setReadBases(Utils.dupBytes((byte)'A',76)); - indelOnlyRead.setBaseQualities(Utils.dupBytes((byte)'@',76)); + indelOnlyRead.setBaseQualities(Utils.dupBytes((byte) '@', 76)); indelOnlyRead.setCigarString("76I"); List reads = Arrays.asList(indelOnlyRead); @@ -148,10 +148,10 @@ public class LocusIteratorByStateUnitTest extends BaseTest { // and considers it to be an indel-containing read. Assert.assertTrue(li.hasNext(),"Should have found a whole-indel read in the normal base pileup without extended events enabled"); AlignmentContext alignmentContext = li.next(); - Assert.assertEquals(alignmentContext.getLocation().getStart(),firstLocus,"Base pileup is at incorrect location."); + Assert.assertEquals(alignmentContext.getLocation().getStart(), firstLocus, "Base pileup is at incorrect location."); ReadBackedPileup basePileup = alignmentContext.getBasePileup(); Assert.assertEquals(basePileup.getReads().size(),1,"Pileup is of incorrect size"); - Assert.assertSame(basePileup.getReads().get(0),indelOnlyRead,"Read in pileup is incorrect"); + Assert.assertSame(basePileup.getReads().get(0), indelOnlyRead, "Read in pileup is incorrect"); } /** @@ -168,7 +168,7 @@ public class LocusIteratorByStateUnitTest extends BaseTest { leadingRead.setCigarString("1M75I"); SAMRecord indelOnlyRead = ArtificialSAMUtils.createArtificialRead(header,"indelOnly",0,secondLocus,76); - indelOnlyRead.setReadBases(Utils.dupBytes((byte)'A',76)); + indelOnlyRead.setReadBases(Utils.dupBytes((byte) 'A', 76)); indelOnlyRead.setBaseQualities(Utils.dupBytes((byte)'@',76)); indelOnlyRead.setCigarString("76I"); @@ -177,7 +177,7 @@ public class LocusIteratorByStateUnitTest extends BaseTest { fullMatchAfterIndel.setBaseQualities(Utils.dupBytes((byte)'@',76)); fullMatchAfterIndel.setCigarString("75I1M"); - List reads = Arrays.asList(leadingRead,indelOnlyRead,fullMatchAfterIndel); + List reads = Arrays.asList(leadingRead, indelOnlyRead, fullMatchAfterIndel); // create the iterator by state with the fake reads and fake records li = makeLTBS(reads, createTestReadProperties()); @@ -204,7 +204,36 @@ public class LocusIteratorByStateUnitTest extends BaseTest { numAlignmentContextsFound++; } - Assert.assertEquals(numAlignmentContextsFound,2,"Found incorrect number of alignment contexts"); + Assert.assertEquals(numAlignmentContextsFound, 2, "Found incorrect number of alignment contexts"); + } + + /** + * Test to make sure that reads supporting only an indel (example cigar string: 76I) do + * not negatively influence the ordering of the pileup. + */ + @Test + public void testWholeIndelReadTest2() { + final int firstLocus = 44367788, secondLocus = firstLocus + 1; + + SAMRecord read = ArtificialSAMUtils.createArtificialRead(header,"read",0,secondLocus,1); + read.setReadBases(Utils.dupBytes((byte) 'A', 1)); + read.setBaseQualities(Utils.dupBytes((byte) '@', 1)); + read.setCigarString("1I"); + + List reads = Arrays.asList(read); + + // create the iterator by state with the fake reads and fake records + li = makeLTBS(reads, createTestReadProperties()); + + while(li.hasNext()) { + AlignmentContext alignmentContext = li.next(); + ReadBackedPileup p = alignmentContext.getBasePileup(); + Assert.assertTrue(p.getNumberOfElements() == 1); + PileupElement pe = p.iterator().next(); + Assert.assertTrue(pe.isBeforeInsertion()); + Assert.assertFalse(pe.isAfterInsertion()); + Assert.assertEquals(pe.getEventBases(), "A"); + } } private static ReadProperties createTestReadProperties() {