private static int UpdateAndAddAlignment(BamAlignment finalRead, bool realignedOther, BamAlignment finalReadOther, List <BamAlignment> reads, INmCalculator nmCalculator, bool recalculateNm) { int nm = 0; if (finalRead != null) { if (realignedOther) { finalRead.MatePosition = finalReadOther.Position; } if (recalculateNm) { nm = nmCalculator.GetNm(finalRead); AddNmTag(finalRead, nm); } reads.Add(finalRead); } return(nm); }
public List <BamAlignment> ExtractReads(PairResult pairResult, INmCalculator nmCalculator, bool doRealign = true, int readsToSilence = 0) { var pair = pairResult.ReadPair; if (pair.PairStatus == PairStatus.LeaveUntouched) { return(pair.GetAlignments().ToList()); } var reads = new List <BamAlignment>(); // TODO clean this up, should really not have two layers (pair result and readpair) here if (pairResult.ReadPair.Stitched) { const bool recalculateNm = true; // Always recalculate NM for stitched reads // TODO more explicitly assume/check that there is actually only one here foreach (var alignment in pairResult.Alignments) { if (doRealign) { var finalReadR1 = RealignSingleAlignment(alignment, out var realignedR1); pair.RealignedR1 = realignedR1; SilenceReads(finalReadR1, null, readsToSilence, realignedR1, false); pair.StitchedNm = UpdateAndAddAlignment(finalReadR1, false, null, reads, nmCalculator, recalculateNm); } else { SilenceReads(alignment, null, readsToSilence, false, false); pair.StitchedNm = UpdateAndAddAlignment(alignment, false, null, reads, nmCalculator, recalculateNm); } } return(reads); } if (pair.IsComplete(false) && (pair.PairStatus == PairStatus.Paired || pair.PairStatus == PairStatus.OffTarget)) { var realignedR1 = false; var realignedR2 = false; var forcedSoftclipR1 = false; var forcedSoftclipR2 = false; var sketchy = false; var origRead1 = pair.Read1; var origRead2 = pair.Read2; int? r1Nm = pair.Read1.GetIntTag("NM"); int? r2Nm = pair.Read2.GetIntTag("NM"); List <PreIndel> pairIndels = null; if (pair.PairStatus == PairStatus.Paired) { if (doRealign) { List <PreIndel> r1Indels = _hasExistingIndels && pairResult.R1Nm <= 2 ? pairResult.OriginalIndelsR1 ?? _indelTargetFinder.FindIndels(origRead1, _chromosome) : _emptyList; List <PreIndel> r2Indels = _hasExistingIndels && pairResult.R2Nm <= 2 ? pairResult.OriginalIndelsR2 ?? _indelTargetFinder.FindIndels(origRead2, _chromosome) : _emptyList; if (_pairAware && _hasExistingIndels && (r1Indels.Any() || r2Indels.Any())) { pairIndels = _finder.GetPairSpecificIndels(pair, r1Indels, r2Indels, ref r1Nm, ref r2Nm); } var confirmedAccepted = new List <HashableIndel>(); bool confirmedR1; bool confirmedR2; // TODO should we pay attention to whether one already has an indel and one doesn't, and realign/confirm the one that does, or that has the better one, first? var try1Read1 = _evaluator.GetFinalAlignment(origRead1, out realignedR1, out forcedSoftclipR1, out confirmedR1, out sketchy, selectedIndels: pairIndels, existingIndels: r1Indels, confirmedAccepteds: confirmedAccepted, mateIndels: r2Indels); pair.Read1 = try1Read1; if ((realignedR1 || confirmedR1) && confirmedAccepted.Any()) { pair.Read2 = _evaluator.GetFinalAlignment(origRead2, out realignedR2, out forcedSoftclipR2, out confirmedR2, out sketchy, selectedIndels: pairIndels, existingIndels: r2Indels, confirmedAccepteds: confirmedAccepted); } else { confirmedAccepted.Clear(); var try1Read2 = _evaluator.GetFinalAlignment(origRead2, out realignedR2, out forcedSoftclipR2, out confirmedR2, out sketchy, selectedIndels: pairIndels, existingIndels: r2Indels, confirmedAccepteds: confirmedAccepted, mateIndels: r1Indels); pair.Read2 = try1Read2; if ((realignedR2 || confirmedR2) && confirmedAccepted.Any()) { pair.Read1 = _evaluator.GetFinalAlignment(origRead1, out realignedR1, out forcedSoftclipR1, out confirmedR1, out sketchy, selectedIndels: pairIndels, existingIndels: r1Indels, confirmedAccepteds: confirmedAccepted); } } pairResult.R1Confirmed = confirmedR1; pairResult.R2Confirmed = confirmedR2; } if (realignedR1 || realignedR2) { pair.Realigned = true; } } pair.RealignedR1 = realignedR1; pair.RealignedR2 = realignedR2; // Silence realigned pair if needed SilenceReads(pair.Read1, pair.Read2, readsToSilence, realignedR1, realignedR2); // Silence original reads in case needed SilenceReads(origRead1, origRead2, readsToSilence, false, false); if (_allowedToStitch && !(forcedSoftclipR1 || forcedSoftclipR2) && (!_skipRestitchIfNothingChanged || (realignedR1 || realignedR2))) { reads = _restitcher.GetRestitchedReads(pair, origRead1, origRead2, r1Nm, r2Nm, pairIndels != null, nmCalculator, realignedR1 || realignedR2 || (r1Nm + r2Nm > 0), sketchy); var isStitched = reads.Count == 1; pair.Stitched = isStitched; pairResult.TriedStitching = true; if (!isStitched) { reads.Clear(); // TODO looks like we are passing through EC twice - here and in the below foreach HandleUnstitchedReads(pair, reads, realignedR1, realignedR2, nmCalculator); } foreach (var bamAlignment in reads) { _evidenceCollector.CollectEvidence(bamAlignment, true, isStitched, _chromosome); } } else { HandleUnstitchedReads(pair, reads, realignedR1, realignedR2, nmCalculator); } } else { if (doRealign) { var finalReadR1 = RealignSingleAlignment(pair.Read1, out var realignedR1); var finalReadR2 = RealignSingleAlignment(pair.Read2, out var realignedR2); pair.RealignedR1 = realignedR1; pair.RealignedR2 = realignedR2; if (realignedR1 || realignedR2) { pair.Realigned = true; } SilenceReads(finalReadR1, finalReadR2, readsToSilence, realignedR1, realignedR2); pair.Nm1 = UpdateAndAddAlignment(finalReadR1, realignedR2, finalReadR2, reads, nmCalculator, realignedR1); pair.Nm2 = UpdateAndAddAlignment(finalReadR2, realignedR1, finalReadR1, reads, nmCalculator, realignedR2); } else { SilenceReads(pair.Read1, pair.Read2, readsToSilence, false, false); pair.Nm1 = UpdateAndAddAlignment(pair.Read1, false, pair.Read2, reads, nmCalculator, false); pair.Nm2 = UpdateAndAddAlignment(pair.Read2, false, pair.Read1, reads, nmCalculator, false); } } return(reads); }
private void HandleUnstitchedReads(ReadPair pair, List <BamAlignment> reads, bool realignedR1, bool realignedR2, INmCalculator nmCalculator) { reads.Add(pair.Read1); reads.Add(pair.Read2); if (realignedR1) { pair.Read2.MatePosition = pair.Read1.Position; _evidenceCollector.CollectEvidence(pair.Read1, true, false, _chromosome); var nm = nmCalculator.GetNm(pair.Read1); pair.Nm1 = nm; AddNmTag(pair.Read1, nm); } if (realignedR2) { pair.Read1.MatePosition = pair.Read2.Position; _evidenceCollector.CollectEvidence(pair.Read2, true, false, _chromosome); var nm = nmCalculator.GetNm(pair.Read1); pair.Nm2 = nm; AddNmTag(pair.Read2, nm); } }
public List <BamAlignment> GetRestitchedReads(ReadPair pair, BamAlignment origRead1, BamAlignment origRead2, int?r1Nm, int?r2Nm, bool realignedAroundPairSpecific, INmCalculator nmCalculator, bool recalculateNm, bool realignmentIsSketchy = false) { var reads = new List <BamAlignment>(); var badRestitchAfterPairSpecificRealign = false; var disagreeingReads = realignedAroundPairSpecific ? ShouldRestitch(pair) : null; if (disagreeingReads == null) { // TODO in some cases, we already tried stitching and then are realigning. // ... If nothing realigned, we don't need to try stitching again as we know it already failed. // ... However, in some cases, we haven't tried stitching yet as we were deferring until realignment. // ... For now, it's ok to leave this here, but know that we are wasting time in some cases trying to stitch the same pair again. int nmStitched = 0; var stitchedReads = _stitchedPairHandler.ExtractReads(pair); if (stitchedReads.Count == 1) { if (recalculateNm) { nmStitched = nmCalculator.GetNm(stitchedReads[0]); pair.StitchedNm = nmStitched; } if (realignedAroundPairSpecific) { // Check that the stitched read represents an overall improvement over the original reads var scStitched = stitchedReads[0].CigarData.GetPrefixClip() + stitchedReads[0].CigarData.GetSuffixClip(); var r1Sc = origRead1.CigarData.GetPrefixClip() + origRead1.CigarData.GetSuffixClip(); var r2Sc = origRead2.CigarData.GetPrefixClip() + origRead2.CigarData.GetSuffixClip(); var origMess1 = r1Nm + r1Sc; var origMess2 = r2Nm + r2Sc; var stitchedMess = nmStitched + scStitched; if (stitchedMess > (origMess1 + origMess2)) { badRestitchAfterPairSpecificRealign = true; } } if (!badRestitchAfterPairSpecificRealign) { _statusHandler.AddStatusCount($"Successfully stitched after realign (ps: {realignedAroundPairSpecific})"); _statusHandler.AddCombinedStatusStringTags("OC", pair.Read1, pair.Read2, stitchedReads[0]); _statusHandler.AddCombinedStatusStringTags("OS", pair.Read1, pair.Read2, stitchedReads[0]); _statusHandler.AddCombinedStatusStringTags("RS", pair.Read1, pair.Read2, stitchedReads[0]); _statusHandler.AddCombinedStatusStringTags("RC", pair.Read1, pair.Read2, stitchedReads[0]); _statusHandler.AddCombinedStatusStringTags("RX", pair.Read1, pair.Read2, stitchedReads[0]); stitchedReads[0].ReplaceOrAddStringTag("SC", pair.Read1.GetStringTag("SC") + pair.Read1.CigarData + "," + pair.Read2.CigarData); stitchedReads[0].ReplaceOrAddIntTag("NM", nmStitched, true); foreach (var tag in _tagsToKeepFromR1) { var r1Tag = pair.Read1.GetStringTag(tag); if (r1Tag != null) { stitchedReads[0].ReplaceOrAddStringTag(tag, r1Tag); } } } } else { pair.FailForOtherReason = true; if (realignmentIsSketchy) { badRestitchAfterPairSpecificRealign = true; } _statusHandler.AddStatusCount($"Failed stitching after realign (ps: {realignedAroundPairSpecific})"); _statusHandler.AppendStatusStringTag("RC", $"Bad after attempted pair-specific realign (ps: {realignedAroundPairSpecific})", origRead1); _statusHandler.AppendStatusStringTag("RC", $"Bad after attempted pair-specific realign (ps: {realignedAroundPairSpecific})", origRead2); } if (badRestitchAfterPairSpecificRealign) { _statusHandler.AddStatusCount($"Restitching was too messy after realign (ps: {realignedAroundPairSpecific})"); _statusHandler.AppendStatusStringTag("RC", "BadRestitchAfterPairSpecificRealign", origRead1); _statusHandler.AppendStatusStringTag("RC", "BadRestitchAfterPairSpecificRealign", origRead2); pair.BadRestitch = true; // Go back to the originals reads.Add(origRead1); reads.Add(origRead2); } else { reads = stitchedReads; } } else { pair.Disagree = true; return(disagreeingReads); } return(reads); }