/** * This method splits blocks whose boundaries contain a read deletion. * * @param blocks * @param alignmentEntry * @return */ private ObjectArrayList<AlignmentBlock> introduceDeletions( ObjectArrayList<AlignmentBlock> blocks, Alignments.AlignmentEntry alignmentEntry) { ObjectArrayList<AlignmentBlock> newBlocks = new ObjectArrayList<AlignmentBlock>(); for (Alignments.SequenceVariation var : alignmentEntry.getSequenceVariationsList()) { for (AlignmentBlock block : blocks) { if (!block.isSoftClipped()) { final int vrPos = var.getPosition() + entry.getPosition(); if (hasReadDeletion(var) && vrPos >= block.getStart() && vrPos <= block.getEnd()) { ByteList leftBases = new ByteArrayList(block.getBases()); ByteList leftScores = new ByteArrayList(block.getQualities()); ByteList rightBases = new ByteArrayList(block.getBases()); ByteList rightScores = new ByteArrayList(block.getQualities()); int deletionPosition = var.getPosition() - 1; leftBases = leftBases.subList(0, deletionPosition); rightBases = rightBases.subList(deletionPosition, rightBases.size()); leftScores = leftScores.subList(0, deletionPosition); rightScores = rightScores.subList(deletionPosition, rightScores.size()); AlignmentBlock left = AlignmentBlock.getInstance( block.getStart(), leftBases.toByteArray(new byte[leftBases.size()]), leftScores.toByteArray(new byte[leftScores.size()]), this); AlignmentBlock right = AlignmentBlock.getInstance( block.getStart() + leftBases.size() + var.getFrom().length(), rightBases.toByteArray(new byte[rightBases.size()]), rightScores.toByteArray(new byte[rightScores.size()]), this); blocks.remove(block); newBlocks.add(left); newBlocks.add(right); } } } } newBlocks.addAll(blocks); return newBlocks; }
/** * Construct alignment blocks from the Goby alignment entry. This method uses the convention that * '=' denotes a match to the reference. * * <p>Conventions for storing sequence variations in Goby alignments are described <a * href="http://tinyurl.com/goby-sequence-variations">here</a> * * @param alignmentEntry The Goby alignment entry to use */ public void buildBlocks(Alignments.AlignmentEntry alignmentEntry) { ObjectArrayList<AlignmentBlock> blocks = new ObjectArrayList<AlignmentBlock>(); ObjectArrayList<AlignmentBlock> insertionBlocks = new ObjectArrayList<AlignmentBlock>(); int start = alignmentEntry.getPosition(); ByteArrayList bases = new ByteArrayList(); ByteArrayList scores = new ByteArrayList(); int readLength = alignmentEntry.getQueryLength(); byte[] readBases = new byte[readLength]; byte[] readQual = new byte[readLength]; Arrays.fill(readBases, (byte) '='); if (alignmentEntry.hasReadQualityScores()) { readQual = alignmentEntry.getReadQualityScores().toByteArray(); } else { Arrays.fill(readQual, (byte) 40); } int j = 0; int insertedBases = 0; int deletedBases = 0; final int leftPadding = alignmentEntry.getQueryPosition(); boolean showSoftClipped = PreferenceManager.getInstance().getAsBoolean(PreferenceManager.SAM_SHOW_SOFT_CLIPPED); if (showSoftClipped && entry.hasSoftClippedBasesLeft()) { int clipLength = entry.getSoftClippedBasesLeft().length(); addSoftClipBlock( blocks, Math.max(0, entry.getPosition() - clipLength), entry.getSoftClippedBasesLeft(), readQual, entry.hasSoftClippedQualityLeft(), entry.getSoftClippedQualityLeft().toByteArray(), 0); } for (Alignments.SequenceVariation var : alignmentEntry.getSequenceVariationsList()) { final String from = var.getFrom(); final int fromLength = from.length(); final String to = var.getTo(); final int toLength = from.length(); final int sequenceVariationLength = Math.max(fromLength, toLength); final ByteString toQuality = var.getToQuality(); if (hasReadInsertion(from)) { bases.clear(); scores.clear(); for (int i = 0; i < sequenceVariationLength; i++) { final char toChar = i >= toLength ? '-' : to.charAt(i); int size = toQuality.size(); final byte qual = size > 0 && i < size ? toQuality.byteAt(i) : 40; bases.add((byte) toChar); scores.add(qual); deletedBases++; } addBlock(insertionBlocks, alignmentEntry.getPosition() + var.getPosition(), bases, scores); bases.clear(); scores.clear(); } else if (!to.contains("-")) { for (int i = 0; i < toLength; i++) { final int offset = j + var.getPosition() + i - 1 + leftPadding - insertedBases; if (offset > 0 && offset < readBases.length) { readBases[offset] = (byte) to.charAt(i); if (i < toQuality.size()) { readQual[offset] = toQuality.byteAt(i); } } } } else { // has read deletion: insertedBases++; } } int pos = start; int matchLength = alignmentEntry.getQueryAlignedLength() - deletedBases; int endAlignmentRefPosition = matchLength + start; bases.clear(); scores.clear(); int maxIndex = Math.min(readBases.length, readQual.length); while (pos < endAlignmentRefPosition) { final int index = pos - start + leftPadding; if (index < maxIndex) { bases.add(readBases[index]); scores.add(readQual[index]); } else { break; } ++pos; } addBlock(blocks, start, bases, scores); blocks = introduceDeletions(blocks, entry); if (showSoftClipped && entry.hasSoftClippedBasesRight()) { int targetAlignedLength = entry.getTargetAlignedLength(); addSoftClipBlock( blocks, entry.getPosition() + targetAlignedLength, entry.getSoftClippedBasesRight(), readQual, entry.hasSoftClippedQualityRight(), entry.getSoftClippedQualityRight().toByteArray(), entry.getQueryAlignedLength() + entry.getSoftClippedBasesLeft().length()); } block = blocks.toArray(new AlignmentBlock[blocks.size()]); Arrays.sort(block, blockComparator); insertionBlock = insertionBlocks.toArray(new AlignmentBlock[insertionBlocks.size()]); Arrays.sort(insertionBlock, blockComparator); ObjectArrayList<GobyAlignment> list = null; if (alignmentEntry.hasSplicedForwardAlignmentLink() || alignmentEntry.hasSplicedBackwardAlignmentLink()) { // if has a forward link, store a reference to this alignment in the reader (which represents // the window scope) list = iterator.cacheSpliceComponent(this); if (list.size() > 1 && spliceListIsValid(list)) { final GobyAlignment spliceHeadAlignment = list.get(0); ObjectArrayList<AlignmentBlock> splicedBlocks = new ObjectArrayList<AlignmentBlock>(); splicedBlocks.addAll(ObjectArrayList.wrap(spliceHeadAlignment.block)); splicedBlocks.addAll(blocks); spliceHeadAlignment.block = splicedBlocks.toArray(new AlignmentBlock[splicedBlocks.size()]); ObjectArrayList<AlignmentBlock> splicedInsertionBlocks = new ObjectArrayList<AlignmentBlock>(); splicedInsertionBlocks.addAll(ObjectArrayList.wrap(spliceHeadAlignment.insertionBlock)); splicedInsertionBlocks.addAll(insertionBlocks); spliceHeadAlignment.insertionBlock = splicedInsertionBlocks.toArray(new AlignmentBlock[splicedInsertionBlocks.size()]); if (spliceHeadAlignment.gapTypes == null) { spliceHeadAlignment.gapTypes = new CharArrayList(10); } spliceHeadAlignment.gapTypes.add(SamAlignment.SKIPPED_REGION); // Since the previous alignment carries this information, we clear up block and // insertionBlock // in this alignment, but keep any softClips: this.block = keepSoftClips(block); this.insertionBlock = new AlignmentBlock[0]; } } }