Finally reinstate the iterator-style interface. Get rid of some scaffolding code.
git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@2052 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
parent
103763fc84
commit
ce5034dc5d
|
|
@ -4,11 +4,12 @@ import org.broadinstitute.sting.gatk.walkers.ReadWalker;
|
||||||
import org.broadinstitute.sting.utils.BaseUtils;
|
import org.broadinstitute.sting.utils.BaseUtils;
|
||||||
import org.broadinstitute.sting.utils.StingException;
|
import org.broadinstitute.sting.utils.StingException;
|
||||||
import org.broadinstitute.sting.utils.cmdLine.Argument;
|
import org.broadinstitute.sting.utils.cmdLine.Argument;
|
||||||
import org.broadinstitute.sting.alignment.Alignment;
|
|
||||||
import org.broadinstitute.sting.alignment.bwa.c.BWACAligner;
|
import org.broadinstitute.sting.alignment.bwa.c.BWACAligner;
|
||||||
import org.broadinstitute.sting.alignment.bwa.c.BWACConfiguration;
|
import org.broadinstitute.sting.alignment.bwa.c.BWACConfiguration;
|
||||||
import net.sf.samtools.SAMRecord;
|
import net.sf.samtools.SAMRecord;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates alignments against existing reads.
|
* Validates alignments against existing reads.
|
||||||
*
|
*
|
||||||
|
|
@ -32,11 +33,6 @@ public class AlignmentValidationWalker extends ReadWalker<Integer,Integer> {
|
||||||
*/
|
*/
|
||||||
private int count = 0;
|
private int count = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Max delta in mapping quality.
|
|
||||||
*/
|
|
||||||
private int maxMapQDelta = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an aligner object. The aligner object will load and hold the BWT until close() is called.
|
* Create an aligner object. The aligner object will load and hold the BWT until close() is called.
|
||||||
*/
|
*/
|
||||||
|
|
@ -69,18 +65,18 @@ public class AlignmentValidationWalker extends ReadWalker<Integer,Integer> {
|
||||||
if(read.getReadNegativeStrandFlag()) bases = BaseUtils.simpleReverseComplement(bases);
|
if(read.getReadNegativeStrandFlag()) bases = BaseUtils.simpleReverseComplement(bases);
|
||||||
|
|
||||||
boolean matches = true;
|
boolean matches = true;
|
||||||
Alignment[] alignments = aligner.getAlignments(bases);
|
Iterator<Alignment[]> alignments = aligner.getAlignments(bases);
|
||||||
|
|
||||||
if(alignments.length == 0 && !read.getReadUnmappedFlag())
|
if(!alignments.hasNext()) {
|
||||||
matches = false;
|
matches = read.getReadUnmappedFlag();
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
for(Alignment alignment: alignments) {
|
Alignment[] alignmentsOfBestQuality = alignments.next();
|
||||||
|
for(Alignment alignment: alignmentsOfBestQuality) {
|
||||||
matches = (alignment.getContigIndex() == read.getReferenceIndex());
|
matches = (alignment.getContigIndex() == read.getReferenceIndex());
|
||||||
matches &= (alignment.getAlignmentStart() == read.getAlignmentStart());
|
matches &= (alignment.getAlignmentStart() == read.getAlignmentStart());
|
||||||
matches &= (alignment.isNegativeStrand() == read.getReadNegativeStrandFlag());
|
matches &= (alignment.isNegativeStrand() == read.getReadNegativeStrandFlag());
|
||||||
matches &= (alignment.getCigar().equals(read.getCigar()));
|
matches &= (alignment.getCigar().equals(read.getCigar()));
|
||||||
int mapQDelta = Math.abs(alignment.getMappingQuality()-read.getMappingQuality());
|
|
||||||
maxMapQDelta = Math.max(mapQDelta,maxMapQDelta);
|
|
||||||
matches &= (alignment.getMappingQuality() == read.getMappingQuality());
|
matches &= (alignment.getMappingQuality() == read.getMappingQuality());
|
||||||
if(matches) break;
|
if(matches) break;
|
||||||
}
|
}
|
||||||
|
|
@ -94,13 +90,14 @@ public class AlignmentValidationWalker extends ReadWalker<Integer,Integer> {
|
||||||
logger.error(String.format(" Negative strand: %b", read.getReadNegativeStrandFlag()));
|
logger.error(String.format(" Negative strand: %b", read.getReadNegativeStrandFlag()));
|
||||||
logger.error(String.format(" Cigar: %s%n", read.getCigarString()));
|
logger.error(String.format(" Cigar: %s%n", read.getCigarString()));
|
||||||
logger.error(String.format(" Mapping quality: %s%n", read.getMappingQuality()));
|
logger.error(String.format(" Mapping quality: %s%n", read.getMappingQuality()));
|
||||||
for(int i = 0; i < alignments.length; i++) {
|
Alignment[] allAlignments = aligner.getAllAlignments(bases);
|
||||||
|
for(int i = 0; i < allAlignments.length; i++) {
|
||||||
logger.error(String.format("Alignment %d:",i));
|
logger.error(String.format("Alignment %d:",i));
|
||||||
logger.error(String.format(" Contig index: %d",alignments[i].getContigIndex()));
|
logger.error(String.format(" Contig index: %d",allAlignments[i].getContigIndex()));
|
||||||
logger.error(String.format(" Alignment start: %d", alignments[i].getAlignmentStart()));
|
logger.error(String.format(" Alignment start: %d", allAlignments[i].getAlignmentStart()));
|
||||||
logger.error(String.format(" Negative strand: %b", alignments[i].isNegativeStrand()));
|
logger.error(String.format(" Negative strand: %b", allAlignments[i].isNegativeStrand()));
|
||||||
logger.error(String.format(" Cigar: %s", alignments[i].getCigarString()));
|
logger.error(String.format(" Cigar: %s", allAlignments[i].getCigarString()));
|
||||||
logger.error(String.format(" Mapping quality: %s%n", alignments[i].getMappingQuality()));
|
logger.error(String.format(" Mapping quality: %s%n", allAlignments[i].getMappingQuality()));
|
||||||
}
|
}
|
||||||
throw new StingException(String.format("Read %s mismatches!", read.getReadName()));
|
throw new StingException(String.format("Read %s mismatches!", read.getReadName()));
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +134,6 @@ public class AlignmentValidationWalker extends ReadWalker<Integer,Integer> {
|
||||||
@Override
|
@Override
|
||||||
public void onTraversalDone(Integer result) {
|
public void onTraversalDone(Integer result) {
|
||||||
aligner.close();
|
aligner.close();
|
||||||
out.printf("Max mapping quality delta: %s%n", maxMapQDelta);
|
|
||||||
super.onTraversalDone(result);
|
super.onTraversalDone(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import org.broadinstitute.sting.alignment.bwa.c.BWACConfiguration;
|
||||||
import net.sf.samtools.SAMRecord;
|
import net.sf.samtools.SAMRecord;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Align reads to the reference specified by BWTPrefix.
|
* Align reads to the reference specified by BWTPrefix.
|
||||||
|
|
@ -45,10 +46,17 @@ public class AlignmentWalker extends ReadWalker<Integer,Integer> {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Integer map(char[] ref, SAMRecord read) {
|
public Integer map(char[] ref, SAMRecord read) {
|
||||||
SAMRecord[] alignedReads = aligner.align(read);
|
Iterator<SAMRecord[]> alignedReads = aligner.align(read);
|
||||||
SAMRecord selectedRead = alignedReads[random.nextInt(alignedReads.length)];
|
if(alignedReads.hasNext()) {
|
||||||
out.println(selectedRead.format());
|
SAMRecord[] bestAlignments = alignedReads.next();
|
||||||
return alignedReads.length;
|
SAMRecord selectedRead = bestAlignments[random.nextInt(bestAlignments.length)];
|
||||||
|
out.println(selectedRead.format());
|
||||||
|
return bestAlignments.length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.println(read.format());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import org.broadinstitute.sting.utils.BaseUtils;
|
||||||
import org.broadinstitute.sting.alignment.Alignment;
|
import org.broadinstitute.sting.alignment.Alignment;
|
||||||
import org.broadinstitute.sting.alignment.bwa.c.BWACConfiguration;
|
import org.broadinstitute.sting.alignment.bwa.c.BWACConfiguration;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An aligner using the BWA/C implementation.
|
* An aligner using the BWA/C implementation.
|
||||||
*
|
*
|
||||||
|
|
@ -50,15 +54,90 @@ public class BWACAligner {
|
||||||
destroy(thunkPointer);
|
destroy(thunkPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a iterator of alignments, batched by mapping quality.
|
||||||
|
* @param bases List of bases.
|
||||||
|
* @return Iterator to alignments.
|
||||||
|
*/
|
||||||
|
public Iterator<Alignment[]> getAlignments(byte[] bases) {
|
||||||
|
final Alignment[] alignments = getAllAlignments(bases);
|
||||||
|
return new Iterator<Alignment[]>() {
|
||||||
|
/**
|
||||||
|
* The last position accessed.
|
||||||
|
*/
|
||||||
|
private int position = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether all alignments have been seen based on the current position.
|
||||||
|
* @return True if any more alignments are pending. False otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasNext() { return position < alignments.length; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the next cross-section of alignments, based on mapping quality.
|
||||||
|
* @return Array of the next set of alignments of a given mapping quality.
|
||||||
|
*/
|
||||||
|
public Alignment[] next() {
|
||||||
|
if(position >= alignments.length)
|
||||||
|
throw new UnsupportedOperationException("Out of alignments to return.");
|
||||||
|
int mapQ = alignments[position].getMappingQuality();
|
||||||
|
int startingPosition = position;
|
||||||
|
while(position < alignments.length && alignments[position].getMappingQuality() == mapQ) position++;
|
||||||
|
return Arrays.copyOfRange(alignments,startingPosition,position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported.
|
||||||
|
*/
|
||||||
|
public void remove() { throw new UnsupportedOperationException("Cannot remove from an alignment iterator"); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Align the given base array to the BWT. The base array should be in ASCII format.
|
* Align the given base array to the BWT. The base array should be in ASCII format.
|
||||||
* @param bases ASCII representation of byte array.
|
* @param bases ASCII representation of byte array.
|
||||||
* @return an array of indices into the bwa.
|
* @return an array of indices into the bwa.
|
||||||
*/
|
*/
|
||||||
public Alignment[] getAlignments(byte[] bases) {
|
public Alignment[] getAllAlignments(byte[] bases) {
|
||||||
if(thunkPointer == 0)
|
if(thunkPointer == 0)
|
||||||
throw new StingException("BWA/C align attempted, but BWA/C was never properly initialized.");
|
throw new StingException("BWA/C align attempted, but BWA/C was never properly initialized.");
|
||||||
return getAlignments(thunkPointer,bases);
|
Alignment[] alignments = getAlignments(thunkPointer,bases);
|
||||||
|
Arrays.sort(alignments,new AlignmentMapQComparator());
|
||||||
|
return alignments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a iterator of aligned reads, batched by mapping quality.
|
||||||
|
* @param read Read to align.
|
||||||
|
* @return Iterator to alignments.
|
||||||
|
*/
|
||||||
|
public Iterator<SAMRecord[]> align(final SAMRecord read) {
|
||||||
|
final Iterator<Alignment[]> alignments = getAlignments(read.getReadBases());
|
||||||
|
return new Iterator<SAMRecord[]>() {
|
||||||
|
/**
|
||||||
|
* Whether all alignments have been seen based on the current position.
|
||||||
|
* @return True if any more alignments are pending. False otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasNext() { return alignments.hasNext(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the next cross-section of alignments, based on mapping quality.
|
||||||
|
* @return Array of the next set of alignments of a given mapping quality.
|
||||||
|
*/
|
||||||
|
public SAMRecord[] next() {
|
||||||
|
Alignment[] alignmentsOfQuality = alignments.next();
|
||||||
|
SAMRecord[] reads = new SAMRecord[alignmentsOfQuality.length];
|
||||||
|
for(int i = 0; i < alignmentsOfQuality.length; i++) {
|
||||||
|
reads[i] = convertAlignmentToRead(read,alignmentsOfQuality[i]);
|
||||||
|
}
|
||||||
|
return reads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported.
|
||||||
|
*/
|
||||||
|
public void remove() { throw new UnsupportedOperationException("Cannot remove from an alignment iterator"); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -67,30 +146,41 @@ public class BWACAligner {
|
||||||
* @param read The read to align.
|
* @param read The read to align.
|
||||||
* @return A list of potential alignments.
|
* @return A list of potential alignments.
|
||||||
*/
|
*/
|
||||||
public SAMRecord[] align(SAMRecord read) {
|
public SAMRecord[] alignAll(SAMRecord read) {
|
||||||
Alignment[] alignments = getAlignments(read.getReadBases());
|
Alignment[] alignments = getAllAlignments(read.getReadBases());
|
||||||
SAMRecord[] reads = new SAMRecord[alignments.length];
|
SAMRecord[] reads = new SAMRecord[alignments.length];
|
||||||
for(int i = 0; i < alignments.length; i++) {
|
for(int i = 0; i < alignments.length; i++)
|
||||||
try {
|
reads[i] = convertAlignmentToRead(read,alignments[i]);
|
||||||
reads[i] = (SAMRecord)read.clone();
|
|
||||||
reads[i].setReadUmappedFlag(false);
|
|
||||||
reads[i].setAlignmentStart((int)alignments[i].getAlignmentStart());
|
|
||||||
reads[i].setReadNegativeStrandFlag(alignments[i].isNegativeStrand());
|
|
||||||
reads[i].setMappingQuality(alignments[i].getMappingQuality());
|
|
||||||
reads[i].setCigar(alignments[i].getCigar());
|
|
||||||
if(alignments[i].isNegativeStrand()) {
|
|
||||||
reads[i].setReadBases(BaseUtils.reverse(reads[i].getReadBases()));
|
|
||||||
reads[i].setBaseQualities(BaseUtils.reverse(reads[i].getBaseQualities()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(CloneNotSupportedException ex) {
|
|
||||||
throw new StingException("Unable to create aligned read from template.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reads;
|
return reads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a read directly from an alignment.
|
||||||
|
* @param unmappedRead Source of the unmapped read. Should have bases, quality scores, and flags.
|
||||||
|
* @param alignment The target alignment for this read.
|
||||||
|
* @return A mapped alignment.
|
||||||
|
*/
|
||||||
|
public SAMRecord convertAlignmentToRead(SAMRecord unmappedRead, Alignment alignment) {
|
||||||
|
SAMRecord read = null;
|
||||||
|
try {
|
||||||
|
read = (SAMRecord)unmappedRead.clone();
|
||||||
|
read.setReadUmappedFlag(false);
|
||||||
|
read.setAlignmentStart((int)alignment.getAlignmentStart());
|
||||||
|
read.setReadNegativeStrandFlag(alignment.isNegativeStrand());
|
||||||
|
read.setMappingQuality(alignment.getMappingQuality());
|
||||||
|
read.setCigar(alignment.getCigar());
|
||||||
|
if(alignment.isNegativeStrand()) {
|
||||||
|
read.setReadBases(BaseUtils.reverse(read.getReadBases()));
|
||||||
|
read.setBaseQualities(BaseUtils.reverse(read.getBaseQualities()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(CloneNotSupportedException ex) {
|
||||||
|
throw new StingException("Unable to create aligned read from template.");
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller to the . The base array should be in
|
* Caller to the . The base array should be in
|
||||||
* ASCII format.
|
* ASCII format.
|
||||||
|
|
@ -98,4 +188,22 @@ public class BWACAligner {
|
||||||
* @param bases ASCII representation of byte array.
|
* @param bases ASCII representation of byte array.
|
||||||
*/
|
*/
|
||||||
protected native Alignment[] getAlignments(long thunkPointer, byte[] bases);
|
protected native Alignment[] getAlignments(long thunkPointer, byte[] bases);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two alignments based on their mapping quality. The one with the highest mapping quality comes FIRST.
|
||||||
|
*/
|
||||||
|
private class AlignmentMapQComparator implements Comparator<Alignment> {
|
||||||
|
/**
|
||||||
|
* Compares two alignments based on their score. If lhs has a higher mapping quality than
|
||||||
|
* rhs, the score will be negative.
|
||||||
|
* @param lhs Left-hand side for comparison.
|
||||||
|
* @param rhs Right-hand side for comparison.
|
||||||
|
* @return Negative value if lhs' score is highe
|
||||||
|
*/
|
||||||
|
public int compare(Alignment lhs, Alignment rhs) {
|
||||||
|
// NOTE: this strategy works because Integer.MAX_VALUE, Integer.MIN_VALUE >> than valid range of mapping
|
||||||
|
// qualities.
|
||||||
|
return rhs.getMappingQuality() - lhs.getMappingQuality();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue