package org.broadinstitute.sting.alignment.bwa; import org.broadinstitute.sting.alignment.Alignment; import org.broadinstitute.sting.utils.StingException; import net.sf.samtools.Cigar; /** * An alignment object to be used incrementally as the BWA aligner * inspects the read. * * @author mhanna * @version 0.1 */ public class BWAAlignment implements Alignment, Cloneable { /** * Track the number of alignments that have been created. */ private static long numCreated; /** * Which number alignment is this? */ private long creationNumber; /** * The aligner performing the alignments. */ protected BWAAligner aligner; /** * Start of the final alignment. */ protected int alignmentStart; /** * Is this match being treated as a negative or positive strand? */ protected boolean negativeStrand; /** * The sequence of matches/mismatches/insertions/deletions. */ private AlignmentMatchSequence alignmentMatchSequence = new AlignmentMatchSequence(); /** * Working variable. How many bases have been matched at this point. */ protected int position; /** * Working variable. How many mismatches have been encountered at this point. */ private int mismatches; /** * Number of gap opens in alignment. */ private int gapOpens; /** * Number of gap extensions in alignment. */ private int gapExtensions; /** * Working variable. The lower bound of the alignment within the BWT. */ protected int loBound; /** * Working variable. The upper bound of the alignment within the BWT. */ protected int hiBound; /** * Cache the score. */ private int score; /** * Gets the starting position for the given alignment. * @return Starting position. */ public int getAlignmentStart() { return alignmentStart; } /** * Is the given alignment on the reverse strand? * @return True if the alignment is on the reverse strand. */ public boolean isNegativeStrand() { return negativeStrand; } public Cigar getCigar() { return alignmentMatchSequence.convertToCigar(isNegativeStrand()); } /** * Gets the current state of this alignment (state of the last base viewed).. * @return Current state of the alignment. */ public AlignmentState getCurrentState() { return alignmentMatchSequence.getCurrentState(); } /** * Adds the given state to the current alignment. * @param state State to add to the given alignment. */ public void addState( AlignmentState state ) { alignmentMatchSequence.addNext(state); } /** * Gets the BWA score of this alignment. * @return BWA-style scores. 0 is best. */ public int getScore() { return score; } public int getMismatches() { return mismatches; } public int getGapOpens() { return gapOpens; } public int getGapExtensions() { return gapExtensions; } public void incrementMismatches() { this.mismatches++; updateScore(); } public void incrementGapOpens() { this.gapOpens++; updateScore(); } public void incrementGapExtensions() { this.gapExtensions++; updateScore(); } /** * Updates the score based on new information about matches / mismatches. */ private void updateScore() { score = mismatches*aligner.MISMATCH_PENALTY + gapOpens*aligner.GAP_OPEN_PENALTY + gapExtensions*aligner.GAP_EXTENSION_PENALTY; } /** * Create a new alignment with the given parent aligner. * @param aligner Aligner being used. */ public BWAAlignment( BWAAligner aligner ) { this.aligner = aligner; this.creationNumber = numCreated++; } /** * Clone the alignment. * @return New instance of the alignment. */ public BWAAlignment clone() { BWAAlignment newAlignment = null; try { newAlignment = (BWAAlignment)super.clone(); } catch( CloneNotSupportedException ex ) { throw new StingException("Unable to clone BWAAlignment."); } newAlignment.creationNumber = numCreated++; newAlignment.alignmentMatchSequence = alignmentMatchSequence.clone(); return newAlignment; } /** * How many bases in the read match the given state. * @param state State to test. * @return number of bases which match that state. */ public int getNumberOfBasesMatchingState(AlignmentState state) { return alignmentMatchSequence.getNumberOfBasesMatchingState(state); } /** * Compare this alignment to another alignment. * @param rhs Other alignment to which to compare. * @return < 0 if this < other, == 0 if this == other, > 0 if this > other */ public int compareTo(Alignment rhs) { BWAAlignment other = (BWAAlignment)rhs; // If the scores are different, disambiguate using the score. if(score != other.score) return score > other.score ? 1 : -1; // Otherwise, use the order in which the elements were created. if(this.creationNumber != other.creationNumber) return this.creationNumber > other.creationNumber ? -1 : 1; return 0; } public String toString() { return String.format("position: %d, strand: %b, state: %s, mismatches: %d, gap opens: %d, gap extensions: %d, loBound: %d, hiBound: %d, score: %d, creationNumber: %d", position, negativeStrand, alignmentMatchSequence.getCurrentState(), mismatches, gapOpens, gapExtensions, loBound, hiBound, getScore(), creationNumber); } }