/// <summary> /// Warning. This algorithm has an inherent assumption: /// the VS must be in order of their true position (first base of difference). /// Thats not always how they appeared in the vcf. /// </summary> /// <param name="allele"></param> /// <param name="clusterVariantSites"></param> /// <param name="referenceSequence"></param> /// <param name="neighborhoodDepthAtSites"></param> /// <param name="clusterCountsAtSites"></param> /// <param name="chromosome"></param> /// <returns></returns> public static CalledAllele Create(string chromosome, int alleleCoordinate, string alleleReference, string alleleAlternate, int varCount, int noCallCount, int totalCoverage, int refSpt, AlleleCategory category, int qNoiselevel, int maxQscore) { if (totalCoverage < varCount) //sometimes the orignal vcf and the bam dont agree... { totalCoverage = varCount; } // Nima: Commented this line for pics-1017 //refSpt = totalCoverage - varCount; if (category == AlleleCategory.Reference) { refSpt = varCount; } var allele = new CalledAllele(category) { Chromosome = chromosome, ReferencePosition = alleleCoordinate, ReferenceAllele = alleleReference, AlternateAllele = alleleAlternate, TotalCoverage = totalCoverage, Type = category, AlleleSupport = varCount, ReferenceSupport = refSpt, NumNoCalls = noCallCount, VariantQscore = VariantQualityCalculator.AssignPoissonQScore(varCount, totalCoverage, qNoiselevel, maxQscore), NoiseLevelApplied = qNoiselevel }; allele.SetFractionNoCalls(); return(allele); }
private static bool PushThroughRamificationsOfGTChange(CalledAllele VariantA, CalledAllele VariantB, CalledAllele Consensus, int RefCountA, int RefCountB, int DepthA, int DepthB, Genotype GT, int MaxQScore, VariantComparisonCase Case) { int NoiseLevel = Consensus.NoiseLevelApplied; if (((GT == Genotype.HomozygousRef) || (GT == Genotype.RefLikeNoCall)) && (Case == VariantComparisonCase.OneReferenceOneAlternate)) { Consensus.AlternateAllele = "."; Consensus.ReferenceAllele = Consensus.ReferenceAllele.Substring(0, 1); if (VariantA != null) { VariantA.VariantQscore = VariantQualityCalculator.AssignPoissonQScore( RefCountA, DepthA, NoiseLevel, MaxQScore); } if (VariantB != null) { VariantB.VariantQscore = VariantQualityCalculator.AssignPoissonQScore( RefCountB, DepthB, NoiseLevel, MaxQScore); } Consensus.AlleleSupport = Consensus.ReferenceSupport; return(true); } return(false); }
/// <summary> /// Warning. This algorithm has an inherent assumption: /// the VS must be in order of their true position (first base of difference). /// Thats not always how they appeared in the vcf. /// </summary> /// <param name="allele"></param> /// <param name="clusterVariantSites"></param> /// <param name="referenceSequence"></param> /// <param name="neighborhoodDepthAtSites"></param> /// <param name="clusterCountsAtSites"></param> /// <param name="chromosome"></param> /// <returns></returns> public static CalledAllele Create(string chromosome, int alleleCoordinate, string alleleReference, string alleleAlternate, int varCount, int totalCoverage, AlleleCategory category, int qNoiselevel, int maxQscore) { if (totalCoverage < varCount) //sometimes the orignal vcf and the bam dont agree... { totalCoverage = varCount; } if (category == AlleleCategory.Reference) { return(new CalledAllele() { Chromosome = chromosome, Coordinate = alleleCoordinate, Reference = alleleReference, Alternate = alleleAlternate, TotalCoverage = totalCoverage, AlleleSupport = varCount, ReferenceSupport = varCount, VariantQscore = VariantQualityCalculator.AssignPoissonQScore(varCount, totalCoverage, qNoiselevel, maxQscore) }); } return(new CalledAllele(category) { Chromosome = chromosome, Coordinate = alleleCoordinate, Reference = alleleReference, Alternate = alleleAlternate, TotalCoverage = totalCoverage, AlleleSupport = varCount, ReferenceSupport = totalCoverage - varCount, VariantQscore = VariantQualityCalculator.AssignPoissonQScore(varCount, totalCoverage, qNoiselevel, maxQscore) }); }
public void CheckQScoresWithBadInput() { //should never happen, but lets be gracefull //and not crash Assert.Equal(0, VariantQualityCalculator.AssignPoissonQScore(0, 0, 0, 100)); //call count, cov, basecallQ Assert.Equal(0, VariantQualityCalculator.AssignPoissonQScore(0, 0, 20, 100)); //call count, cov, basecallQ Assert.Equal(0, VariantQualityCalculator.AssignPoissonQScore(0, -1, 20, 100)); //call count, cov, basecallQ Assert.Equal(0, VariantQualityCalculator.AssignPoissonQScore(-1, 0, 20, 100)); //call count, cov, basecallQ Assert.Equal(0, VariantQualityCalculator.AssignPoissonQScore(-1, -1, 20, 100)); //call count, cov, basecallQ }
public void SupplementSupportWithClippedReads(CallableNeighborhood neighborhood) { var neighbors = neighborhood.VcfVariantSites; var refName = neighbors.First().ReferenceName; _alignmentExtractor.Jump(refName); Logger.WriteToLog("Supplementing candidate variant support with soft clipped reads."); //var readFilter = new NeighborhoodReadFilter(_options); //var clippedReadComparator = new ClippedReadComparator(); //var mnvClippedReadComparator = new MNVClippedReadComparator(scReadFilter); Read read = new Read(); while (true) { if (!_alignmentExtractor.GetNextAlignment(read)) { break; // no more reads } // Check if clipped part matches alternate allele of any candidate variant foreach (var mnv in neighborhood.CandidateVariants) { // Do not boost support for SNVs and short MNVs if (mnv.ReferenceAllele.Length + mnv.AlternateAllele.Length < _minSizeForClipRescue) { continue; } if (_mnvClippedReadComparator.DoesClippedReadSupportMNV(read, mnv)) { // Nima: in current implementation, same read can support multiple candidate variants. // In future we may want to "assign" reads to only one candidate variant. // Risk: reads that support an MNV, may also support candidate variants. This can lead to false positives. mnv.AlleleSupport++; mnv.SoftClipAlleleSupport++; } } if (read.Position > neighborhood.LastPositionOfInterestWithLookAhead) { break; } } // Update Q score before moving on // Nima: Q score will be calculated twice for some variants // (once in PhasedVariantExtractor.cs>Create() , and another time here) foreach (var mnv in neighborhood.CandidateVariants) { mnv.VariantQscore = VariantQualityCalculator.AssignPoissonQScore(mnv.AlleleSupport, mnv.ReferenceSupport, _qNoiseLevel, _maxQscore); Logger.WriteToLog("Added soft clip support of {0} to MNV: {1}.", mnv.AlleleSupport - mnv.SoftClipAlleleSupport, mnv.ToString()); } }
public static void UpdateVariantQScoreAndRefilter(int maxQscore, int filterQScore, Dictionary <MutationCategory, int> qCalibratedRates, CalledAllele originalVar, MutationCategory cat, bool subsample) { double depth; double callCount; //tjd+ // We can revisit this math at a later date. Exactly how we lower the Qscores // or filter the suspect calls is TBD. We should work with this new algorithm // on a larger collection of datasets representing various alignment issues, // and modify the code/parameters as needed. // A few thoughts: Amplicon edge issues don't get better the deeper you sequence. // We need to scale out depth from the Q score calculation (since the original Q score is a fxn of depth/freq). // One option is to Cap at ~100 DP (TODO, this should be a parameter, a fxn of your bascallquality). // double subSampleToThis = 100; // tjd- double denominator = MathOperations.QtoP(qCalibratedRates[cat]); double subSampleToThis = 1.0 / denominator; if ((qCalibratedRates[cat] == 0) || (denominator == 0)) { subsample = false; } bool canUpdateQ = HaveInfoToUpdateQ(originalVar, out depth, out callCount); if (subsample && (depth > subSampleToThis)) { callCount = callCount * subSampleToThis / depth; depth = subSampleToThis; } if (canUpdateQ) { int newQ = VariantQualityCalculator.AssignPoissonQScore( (int)callCount, (int)depth, qCalibratedRates[cat], Math.Min(originalVar.VariantQscore, maxQscore)); //note, using "originalVar.VariantQscore" and the maxQ stops us from ever RAISING the q score over these values. InsertNewQ(qCalibratedRates, originalVar, cat, newQ, true); //update filters if needed if (newQ < filterQScore) { if (originalVar.Filters.Contains(FilterType.LowVariantQscore)) { return; } originalVar.Filters.Add(FilterType.LowVariantQscore); } } }
public void AssignPoissonQScore() { //If rounded qScore is above maxQScore, should return maxQScore var coverage = 500; var varSupport = 25; var estQuality = 20; var expectedActualQValue = 98; var maxQValue = expectedActualQValue + 1; maxQValue = 1000; double finalQValue = VariantQualityCalculator.AssignPoissonQScore(varSupport, coverage, estQuality, maxQValue); Assert.Equal(expectedActualQValue, finalQValue); maxQValue = expectedActualQValue - 1; finalQValue = VariantQualityCalculator.AssignPoissonQScore(varSupport, coverage, estQuality, maxQValue); Assert.Equal(maxQValue, finalQValue); }
public void Pisces_AssignPValue() { List <int[]> SampleValues = new List <int[]>() //coverage,var calls} { new int[] { 100, 0 }, new int[] { 100, 1 }, new int[] { 100, 5 }, new int[] { 200, 10 }, new int[] { 500, 25 }, new int[] { 5000, 250 }, }; List <double[]> ReturnedValues = new List <double[]>(); { }//p,Q foreach (int[] item in SampleValues) { double pValue = VariantQualityCalculator.AssignPValue(item[1], item[0], 20); double Qscore = MathOperations.PtoQ(pValue); double FinalQValue = VariantQualityCalculator.AssignPoissonQScore(item[1], item[0], 20, 100); double[] Result = new double[] { pValue, Qscore, FinalQValue }; ReturnedValues.Add(Result); } Assert.Equal(ReturnedValues[0][0], 1, 4); Assert.Equal(ReturnedValues[0][2], 0, 4); Assert.Equal(ReturnedValues[1][0], 0.6321, 4); Assert.Equal(ReturnedValues[1][2], 2, 4); Assert.Equal(ReturnedValues[2][0], 0.003659, 4); Assert.Equal(ReturnedValues[2][2], 24, 4); Assert.Equal(ReturnedValues[3][0], 4.65 * Math.Pow(10, -5), 5); Assert.Equal(ReturnedValues[3][2], 43, 4); Assert.Equal(ReturnedValues[4][0], 1.599 * Math.Pow(10, -10), 10); Assert.Equal(ReturnedValues[4][2], 98, 4); Assert.Equal(ReturnedValues[5][0], 0.0, 10); Assert.Equal(ReturnedValues[5][2], 100, 4); }
public static void UpdateVariant(int maxQscore, int filterQScore, Dictionary <MutationCategory, int> qCalibratedRates, VcfVariant originalVar, MutationCategory cat) { int depth; int callCount; bool canUpdateQ = HaveInfoToUpdateQ(originalVar, out depth, out callCount); if (canUpdateQ) { int newQ = VariantQualityCalculator.AssignPoissonQScore( callCount, depth, qCalibratedRates[cat], maxQscore); InsertNewQ(qCalibratedRates, originalVar, cat, newQ); //update filters if needed if (newQ < filterQScore) { var vcfConfig = new VcfWriterConfig(); vcfConfig.VariantQualityFilterThreshold = filterQScore; var formatter = new VcfFormatter(vcfConfig); string lowQString = formatter.MapFilter(FilterType.LowVariantQscore); string passString = VcfFormatter.PassFilter; if (originalVar.Filters.Contains(lowQString)) { return; } if (originalVar.Filters == passString) { originalVar.Filters = lowQString; } else { originalVar.Filters += VcfFormatter.FilterSeparator + lowQString; } } } }
public void EvaluateVariants() { var config = new VariantCallerConfig { MaxVariantQscore = 100, NoiseLevelUsedForQScoring = 20, ChrReference = new ChrReference { Sequence = "ACGTACGT", Name = "Boo" }, GenotypeCalculator = new SomaticGenotyper(), LocusProcessor = new SomaticLocusProcessor() }; var variantCaller = new AlleleCaller(config); var highCoverageCoordinate = 123; var lowCoverageCoordinate = 456; var passingVariant = new CandidateAllele("chr1", highCoverageCoordinate, "A", "T", AlleleCategory.Snv) { SupportByDirection = new[] { 500, 0, 0 } // Freq is 500/1500, q is 100 }; var passingVariant2 = new CandidateAllele("chr1", highCoverageCoordinate, "A", "C", AlleleCategory.Snv) { SupportByDirection = new[] { 500, 0, 0 } // Freq is 500/1500, q is 100 }; var lowFreqVariant = new CandidateAllele("chr2", highCoverageCoordinate, "A", "T", AlleleCategory.Snv) { SupportByDirection = new[] { 1, 0, 0 } // Freq is 1/1500, q is 0 }; var lowCoverageVariant = new CandidateAllele("chr3", lowCoverageCoordinate, "A", "T", AlleleCategory.Snv) { SupportByDirection = new[] { 10, 0, 0 } // Freq is 10/15, q is 100 }; var lowqVariant = new CandidateAllele("chr4", highCoverageCoordinate, "A", "T", AlleleCategory.Snv) { SupportByDirection = new[] { 40, 0, 0 } // Freq is 40/1500, q is 72 }; var passingReferenceHigh = new CandidateAllele("chr1", highCoverageCoordinate, "A", "A", AlleleCategory.Reference) { SupportByDirection = new[] { 500, 0, 0 } // Freq is 500/1500, q is 100 }; var passingReferenceLow = new CandidateAllele("chr3", lowCoverageCoordinate, "A", "A", AlleleCategory.Reference) { SupportByDirection = new[] { 10, 0, 0 } // Freq is 10/15, q is 100 }; var candidateVariants = new List <CandidateAllele> { passingVariant }; //Variants should be correctly mapped var mockAlleleCountSource = MockStateManager(highCoverageCoordinate, lowCoverageCoordinate).Object; var BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); var BaseCalledAllele = BaseCalledAlleles.First(); Assert.Equal(passingVariant.AlternateAllele, BaseCalledAllele.AlternateAllele); Assert.Equal(passingVariant.ReferenceAllele, BaseCalledAllele.ReferenceAllele); Assert.Equal(passingVariant.Chromosome, BaseCalledAllele.Chromosome); Assert.Equal(passingVariant.ReferencePosition, BaseCalledAllele.ReferencePosition); Assert.Equal(passingVariant.Support, BaseCalledAllele.AlleleSupport); Assert.True(passingVariant.Type != AlleleCategory.Reference); Assert.True(BaseCalledAllele.Type == AlleleCategory.Snv); //After the Calculator steps are performed, variants that don't meet //our requirements to be callable should drop out //High coverage requirement - lowCoverageVariant should drop out. config.MinCoverage = (HighCoverageMultiplier * NumAlleles * NumDirections) - 1; config.IncludeReferenceCalls = false; config.MinVariantQscore = 0; config.MinFrequency = 0; variantCaller = new AlleleCaller(config); candidateVariants = new List <CandidateAllele> { passingVariant, lowFreqVariant, lowCoverageVariant }; BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(2, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); //High coverage but allow reference calls = nothing should drop out config.IncludeReferenceCalls = true; variantCaller = new AlleleCaller(config); candidateVariants = new List <CandidateAllele> { passingVariant, lowFreqVariant, lowCoverageVariant }; BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); foreach (var cvar in BaseCalledAlleles) { Console.WriteLine(cvar.VariantQscore); } Assert.Equal(3, BaseCalledAlleles.Count()); //High frequency requirement - low frequency variant should drop out config.MinCoverage = 0; config.IncludeReferenceCalls = false; config.MinVariantQscore = 0; config.MinFrequency = ((float)lowCoverageVariant.Support + 1) / (HighCoverageMultiplier * NumAlleles * NumDirections); BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(2, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); //High q score requirement - low frequency variant should drop out config.MinCoverage = 0; config.IncludeReferenceCalls = false; config.MinVariantQscore = 0; config.MinFrequency = 0; config.MinVariantQscore = VariantQualityCalculator.AssignPoissonQScore(lowqVariant.Support, (HighCoverageMultiplier * Constants.NumCovContributingAlleleTypes * Constants.NumDirectionTypes), config.NoiseLevelUsedForQScoring, config.MaxVariantQscore) + 1; candidateVariants = new List <CandidateAllele> { passingVariant, passingVariant2, lowFreqVariant, lowCoverageVariant, lowqVariant }; BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(3, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant2))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowqVariant))); //High genotype q score requirement - low GQ variant should filter config.MinCoverage = 0; config.IncludeReferenceCalls = false; config.MinVariantQscore = 0; config.MinFrequency = 0; config.GenotypeCalculator = new DiploidThresholdingGenotyper(); config.LowGTqFilter = 20; config.MaxGenotypeQscore = int.MaxValue; candidateVariants = new List <CandidateAllele> { passingVariant, passingVariant2, lowFreqVariant, lowCoverageVariant, lowqVariant }; variantCaller = new AlleleCaller(config); BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(2, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant2))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowqVariant))); var calledList = BaseCalledAlleles.ToList(); Assert.True(calledList[0].Filters.Contains(FilterType.LowGenotypeQuality)); //1249, forced to 0 for nocall. Assert.True(calledList[1].Filters.Contains(FilterType.LowGenotypeQuality)); //1249, forced to 0 for nocall //Assert.True(calledList[2].Filters.Contains(FilterType.LowGenotypeQuality));//0 pruned //go back to somatic config for the rest of the tests. config.GenotypeCalculator = new SomaticGenotyper(); config.LowGTqFilter = 0; config.MaxGenotypeQscore = 0; config.MinVariantQscore = VariantQualityCalculator.AssignPoissonQScore(lowqVariant.Support, (HighCoverageMultiplier * Constants.NumCovContributingAlleleTypes * Constants.NumDirectionTypes), config.NoiseLevelUsedForQScoring, config.MaxVariantQscore) + 1; // reference calls included candidateVariants = new List <CandidateAllele> { passingReferenceHigh, passingReferenceLow }; variantCaller = new AlleleCaller(config); BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(2, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingReferenceHigh))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingReferenceLow))); // reference calls only included if no passing variant candidateVariants = new List <CandidateAllele> { passingReferenceHigh, passingReferenceLow, passingVariant, passingVariant2, lowFreqVariant, lowCoverageVariant, lowqVariant }; BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(3, BaseCalledAlleles.Count()); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, passingReferenceHigh))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, passingReferenceLow))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant2))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowqVariant))); // reference calls only included if no passing variant (lowCoverageVariant fails) candidateVariants = new List <CandidateAllele> { passingReferenceLow, lowCoverageVariant, }; config.IncludeReferenceCalls = false; config.MinCoverage = (HighCoverageMultiplier * NumAlleles * NumDirections) - 1; variantCaller = new AlleleCaller(config); BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(1, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingReferenceLow))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); // candidates outside of intervals are trimmed off config.MinCoverage = 0; config.MinVariantQscore = 0; config.MinFrequency = 0; variantCaller = new AlleleCaller(config, new ChrIntervalSet(new List <Region>() { new Region(highCoverageCoordinate, lowCoverageCoordinate) }, "chr1")); candidateVariants = new List <CandidateAllele> { passingVariant, lowFreqVariant, lowCoverageVariant }; BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(3, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); variantCaller = new AlleleCaller(config, new ChrIntervalSet(new List <Region>() { new Region(highCoverageCoordinate, highCoverageCoordinate) }, "chr1")); BaseCalledAlleles = variantCaller.Call(new CandidateBatch(candidateVariants), mockAlleleCountSource).Values.SelectMany(v => v); Assert.Equal(2, BaseCalledAlleles.Count()); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, passingVariant))); Assert.True(BaseCalledAlleles.Any(v => MatchVariants(v, lowFreqVariant))); Assert.False(BaseCalledAlleles.Any(v => MatchVariants(v, lowCoverageVariant))); }
private static int CombineQualitiesByPoolingReads(int CallCount, int CovDepth, int EstimatedBaseCallQuality, int MaxQScore) { return(VariantQualityCalculator.AssignPoissonQScore(CallCount, CovDepth, EstimatedBaseCallQuality, MaxQScore)); }