/** * 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)); }
@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; }
@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); }
@Override protected boolean isUsableBase(final PileupElement p) { return super.isUsableBase(p) && p.getRead().getCigar() != null; }
@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(); }