/**
   * Helper function to add the read underneath a pileup element to the map
   *
   * @param p Pileup element
   * @param a Corresponding allele
   * @param likelihood Allele likelihood
   */
  public void add(PileupElement p, Allele a, Double likelihood) {
    if (p == null) throw new IllegalArgumentException("Pileup element cannot be null");
    if (p.getRead() == null)
      throw new IllegalArgumentException("Read underlying pileup element cannot be null");
    if (a == null) throw new IllegalArgumentException("Allele for add() cannot be null");

    add(p.getRead(), a, likelihood);
  }
  /**
   * Computes an allele biased version of the given pileup
   *
   * @param pileup the original pileup
   * @param downsamplingFraction the fraction of total reads to remove per allele
   * @return allele biased pileup
   */
  public static ReadBackedPileup createAlleleBiasedBasePileup(
      final ReadBackedPileup pileup, final double downsamplingFraction) {
    // special case removal of all or no reads
    if (downsamplingFraction <= 0.0) return pileup;
    if (downsamplingFraction >= 1.0)
      return new ReadBackedPileupImpl(pileup.getLocation(), new ArrayList<PileupElement>());

    final PileupElementList[] alleleStratifiedElements = new PileupElementList[4];
    for (int i = 0; i < 4; i++) alleleStratifiedElements[i] = new PileupElementList();

    // start by stratifying the reads by the alleles they represent at this position
    for (final PileupElement pe : pileup) {
      final int baseIndex = BaseUtils.simpleBaseToBaseIndex(pe.getBase());
      if (baseIndex != -1) alleleStratifiedElements[baseIndex].add(pe);
    }

    // make a listing of allele counts and calculate the total count
    final int[] alleleCounts = calculateAlleleCounts(alleleStratifiedElements);
    final int totalAlleleCount = (int) MathUtils.sum(alleleCounts);

    // do smart down-sampling
    final int numReadsToRemove = (int) (totalAlleleCount * downsamplingFraction); // floor
    final int[] targetAlleleCounts = runSmartDownsampling(alleleCounts, numReadsToRemove);

    final HashSet<PileupElement> readsToRemove = new HashSet<PileupElement>(numReadsToRemove);
    for (int i = 0; i < 4; i++) {
      final PileupElementList alleleList = alleleStratifiedElements[i];
      // if we don't need to remove any reads, then don't
      if (alleleCounts[i] > targetAlleleCounts[i])
        readsToRemove.addAll(
            downsampleElements(
                alleleList, alleleCounts[i], alleleCounts[i] - targetAlleleCounts[i]));
    }

    // we need to keep the reads sorted because the FragmentUtils code will expect them in
    // coordinate order and will fail otherwise
    final List<PileupElement> readsToKeep =
        new ArrayList<PileupElement>(totalAlleleCount - numReadsToRemove);
    for (final PileupElement pe : pileup) {
      if (!readsToRemove.contains(pe)) {
        readsToKeep.add(pe);
      }
    }

    return new ReadBackedPileupImpl(
        pileup.getLocation(), new ArrayList<PileupElement>(readsToKeep));
  }
예제 #3
0
  @Override
  public Map<String, Object> annotate(
      final RefMetaDataTracker tracker,
      final AnnotatorCompatible walker,
      final ReferenceContext ref,
      final Map<String, AlignmentContext> stratifiedContexts,
      final VariantContext vc,
      final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
    // Can only call from UnifiedGenotyper
    if (!(walker instanceof UnifiedGenotyper)) {
      if (!walkerIdentityCheckWarningLogged) {
        if (walker != null)
          logger.warn(
              "Annotation will not be calculated, must be called from UnifiedGenotyper, not "
                  + walker.getClass().getName());
        else logger.warn("Annotation will not be calculated, must be called from UnifiedGenotyper");
        walkerIdentityCheckWarningLogged = true;
      }
      return null;
    }

    if (stratifiedContexts.isEmpty()) return null;

    // not meaningful when we're at an indel location: deletions that start at location N are by
    // definition called at the position  N-1, and at position N-1
    // there are no informative deletions in the pileup
    if (!vc.isSNP()) return null;

    int deletions = 0;
    int depth = 0;
    for (Map.Entry<String, AlignmentContext> sample : stratifiedContexts.entrySet()) {
      for (final PileupElement p : sample.getValue().getBasePileup()) {
        depth++;
        if (p.isDeletion()) deletions++;
      }
    }
    Map<String, Object> map = new HashMap<>();
    map.put(
        getKeyNames().get(0),
        String.format("%.2f", depth == 0 ? 0.0 : (double) deletions / (double) depth));
    return map;
  }
예제 #4
0
  @Override
  public CallableBaseState map(
      RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
    CalledState state;

    if (BaseUtils.isNBase(ref.getBase())) {
      state = CalledState.REF_N;
    } else {
      // count up the depths of all and QC+ bases
      int rawDepth = 0, QCDepth = 0, lowMAPQDepth = 0;
      for (PileupElement e : context.getBasePileup()) {
        rawDepth++;

        if (e.getMappingQual() <= maxLowMAPQ) lowMAPQDepth++;

        if (e.getMappingQual() >= minMappingQuality
            && (e.getQual() >= minBaseQuality || e.isDeletion())) {
          QCDepth++;
        }
      }

      // System.out.printf("%s rawdepth = %d QCDepth = %d lowMAPQ = %d%n", context.getLocation(),
      // rawDepth, QCDepth, lowMAPQDepth);
      if (rawDepth == 0) {
        state = CalledState.NO_COVERAGE;
      } else if (rawDepth >= minDepthLowMAPQ
          && MathUtils.ratio(lowMAPQDepth, rawDepth) >= maxLowMAPQFraction) {
        state = CalledState.POOR_MAPPING_QUALITY;
      } else if (QCDepth < minDepth) {
        state = CalledState.LOW_COVERAGE;
      } else if (rawDepth >= maxDepth && maxDepth != -1) {
        state = CalledState.EXCESSIVE_COVERAGE;
      } else {
        state = CalledState.CALLABLE;
      }
    }

    return new CallableBaseState(getToolkit().getGenomeLocParser(), context.getLocation(), state);
  }
  public Event map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {

    boolean hasIndel = false;
    boolean hasInsertion = false;
    boolean hasPointEvent = false;

    int furthestStopPos = -1;

    // look at the rods for indels or SNPs
    if (tracker != null) {
      for (VariantContext vc : tracker.getValues(known)) {
        switch (vc.getType()) {
          case INDEL:
            hasIndel = true;
            if (vc.isSimpleInsertion()) hasInsertion = true;
            break;
          case SNP:
            hasPointEvent = true;
            break;
          case MIXED:
            hasPointEvent = true;
            hasIndel = true;
            if (vc.isSimpleInsertion()) hasInsertion = true;
            break;
          default:
            break;
        }
        if (hasIndel) furthestStopPos = vc.getEnd();
      }
    }

    // look at the normal context to get deletions and positions with high entropy
    final ReadBackedPileup pileup = context.getBasePileup();

    int mismatchQualities = 0, totalQualities = 0;
    final byte refBase = ref.getBase();
    for (PileupElement p : pileup) {

      // check the ends of the reads to see how far they extend
      furthestStopPos = Math.max(furthestStopPos, p.getRead().getAlignmentEnd());

      // is it a deletion or insertion?
      if (p.isDeletion() || p.isBeforeInsertion()) {
        hasIndel = true;
        if (p.isBeforeInsertion()) hasInsertion = true;
      }

      // look for mismatches
      else if (lookForMismatchEntropy) {
        if (p.getBase() != refBase) mismatchQualities += p.getQual();
        totalQualities += p.getQual();
      }
    }

    // make sure we're supposed to look for high entropy
    if (lookForMismatchEntropy
        && pileup.getNumberOfElements() >= minReadsAtLocus
        && (double) mismatchQualities / (double) totalQualities >= mismatchThreshold)
      hasPointEvent = true;

    // return null if no event occurred
    if (!hasIndel && !hasPointEvent) return null;

    // return null if we didn't find any usable reads/rods associated with the event
    if (furthestStopPos == -1) return null;

    GenomeLoc eventLoc = context.getLocation();
    if (hasInsertion)
      eventLoc =
          getToolkit()
              .getGenomeLocParser()
              .createGenomeLoc(eventLoc.getContig(), eventLoc.getStart(), eventLoc.getStart() + 1);

    EVENT_TYPE eventType =
        (hasIndel
            ? (hasPointEvent ? EVENT_TYPE.BOTH : EVENT_TYPE.INDEL_EVENT)
            : EVENT_TYPE.POINT_EVENT);

    return new Event(eventLoc, furthestStopPos, eventType);
  }
예제 #6
0
 @Override
 protected boolean isUsableBase(final PileupElement p) {
   return super.isUsableBase(p) && p.getRead().getCigar() != null;
 }
예제 #7
0
 @Override
 protected Double getElementForPileupElement(final PileupElement p) {
   final int offset = AlignmentUtils.calcAlignmentByteArrayOffset(p.getRead().getCigar(), p, 0, 0);
   return (double) AnnotationUtils.getFinalVariantReadPosition(p.getRead(), offset);
 }
  public Map<Allele, Double> getLikelihoodsAssociatedWithPileupElement(final PileupElement p) {
    if (!likelihoodReadMap.containsKey(p.getRead())) return null;

    return likelihoodReadMap.get(p.getRead());
  }
 /**
  * Does the current map contain the key associated with a particular SAM record in pileup?
  *
  * @param p Pileup element
  * @return true if the map contains pileup element, else false
  */
 public boolean containsPileupElement(final PileupElement p) {
   return likelihoodReadMap.containsKey(p.getRead());
 }
 @Override
 protected Double getElementForPileupElement(final PileupElement p) {
   return (double) p.getQual();
 }