Пример #1
0
 public static Pair<Boolean, CigarElement> readStartsWithInsertion(final Cigar cigar) {
   for (CigarElement cigarElement : cigar.getCigarElements()) {
     if (cigarElement.getOperator() == CigarOperator.INSERTION)
       return new Pair<Boolean, CigarElement>(true, cigarElement);
     else if (cigarElement.getOperator() != CigarOperator.HARD_CLIP
         && cigarElement.getOperator() != CigarOperator.SOFT_CLIP) break;
   }
   return new Pair<Boolean, CigarElement>(false, null);
 }
Пример #2
0
  public static Pair<Integer, Boolean> getReadCoordinateForReferenceCoordinate(
      final int alignmentStart,
      final Cigar cigar,
      final int refCoord,
      final boolean allowGoalNotReached) {
    int readBases = 0;
    int refBases = 0;
    boolean fallsInsideDeletion = false;

    int goal = refCoord - alignmentStart; // The goal is to move this many reference bases
    if (goal < 0) {
      if (allowGoalNotReached) {
        return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
      } else {
        throw new ReviewedStingException(
            "Somehow the requested coordinate is not covered by the read. Too many deletions?");
      }
    }
    boolean goalReached = refBases == goal;

    Iterator<CigarElement> cigarElementIterator = cigar.getCigarElements().iterator();
    while (!goalReached && cigarElementIterator.hasNext()) {
      CigarElement cigarElement = cigarElementIterator.next();
      int shift = 0;

      if (cigarElement.getOperator().consumesReferenceBases()
          || cigarElement.getOperator() == CigarOperator.SOFT_CLIP) {
        if (refBases + cigarElement.getLength() < goal) shift = cigarElement.getLength();
        else shift = goal - refBases;

        refBases += shift;
      }
      goalReached = refBases == goal;

      if (!goalReached && cigarElement.getOperator().consumesReadBases())
        readBases += cigarElement.getLength();

      if (goalReached) {
        // Is this base's reference position within this cigar element? Or did we use it all?
        boolean endsWithinCigar = shift < cigarElement.getLength();

        // If it isn't, we need to check the next one. There should *ALWAYS* be a next one
        // since we checked if the goal coordinate is within the read length, so this is just a
        // sanity check.
        if (!endsWithinCigar && !cigarElementIterator.hasNext()) {
          if (allowGoalNotReached) {
            return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
          } else {
            throw new ReviewedStingException(
                "Reference coordinate corresponds to a non-existent base in the read. This should never happen -- call Mauricio");
          }
        }

        CigarElement nextCigarElement;

        // if we end inside the current cigar element, we just have to check if it is a deletion
        if (endsWithinCigar)
          fallsInsideDeletion = cigarElement.getOperator() == CigarOperator.DELETION;

        // if we end outside the current cigar element, we need to check if the next element is an
        // insertion or deletion.
        else {
          nextCigarElement = cigarElementIterator.next();

          // if it's an insertion, we need to clip the whole insertion before looking at the next
          // element
          if (nextCigarElement.getOperator() == CigarOperator.INSERTION) {
            readBases += nextCigarElement.getLength();
            if (!cigarElementIterator.hasNext()) {
              if (allowGoalNotReached) {
                return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
              } else {
                throw new ReviewedStingException(
                    "Reference coordinate corresponds to a non-existent base in the read. This should never happen -- call Mauricio");
              }
            }

            nextCigarElement = cigarElementIterator.next();
          }

          // if it's a deletion, we will pass the information on to be handled downstream.
          fallsInsideDeletion = nextCigarElement.getOperator() == CigarOperator.DELETION;
        }

        // If we reached our goal outside a deletion, add the shift
        if (!fallsInsideDeletion && cigarElement.getOperator().consumesReadBases())
          readBases += shift;

        // If we reached our goal inside a deletion, but the deletion is the next cigar element then
        // we need
        // to add the shift of the current cigar element but go back to it's last element to return
        // the last
        // base before the deletion (see warning in function contracts)
        else if (fallsInsideDeletion && !endsWithinCigar) readBases += shift - 1;

        // If we reached our goal inside a deletion then we must backtrack to the last base before
        // the deletion
        else if (fallsInsideDeletion && endsWithinCigar) readBases--;
      }
    }

    if (!goalReached) {
      if (allowGoalNotReached) {
        return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
      } else {
        throw new ReviewedStingException(
            "Somehow the requested coordinate is not covered by the read. Alignment "
                + alignmentStart
                + " | "
                + cigar);
      }
    }

    return new Pair<Integer, Boolean>(readBases, fallsInsideDeletion);
  }