Example #1
0
            internal static IWittyerVariant Create([NotNull] IVcfVariant baseVariant,
                                                   string sample, double percentageDistance, uint basepairDistance,
                                                   IReadOnlyList <uint> bins, WittyerVariantType svType)
            {
                if (svType == WittyerVariantType.Invalid)
                {
                    throw new InvalidDataException(
                              $"Invalid {VcfConstants.SvTypeKey} in variant: \n{baseVariant}\nNot sure why you got here though. Check with a witty.er developer!");
                }

                var end          = baseVariant.Position + baseVariant.GetSvLength();
                var baseInterval = BedInterval.Create(baseVariant.Position, end);

                var borderInterval =
                    baseVariant.Position.CalculateBorderInterval(baseInterval,
                                                                 baseVariant.ParseCi(WittyerConstants.Cipos),
                                                                 percentageDistance, basepairDistance);

                // wittyerVariant should all have end border, it's a matter of how to find it,
                // either END key in INFO field, sort out through SVLEN or other ways, details can be defined in FindEndBorder() later
                var endInterval = (end - 1).CalculateBorderInterval(baseInterval,
                                                                    baseVariant.ParseCi(WittyerConstants.Ciend),
                                                                    percentageDistance, basepairDistance);

                var posContigAndInterval =
                    ContigAndInterval.Create(baseVariant.Contig, borderInterval.Start, borderInterval.Stop + 1);
                var endContigAndInterval =
                    ContigAndInterval.Create(baseVariant.Contig, endInterval.Start, endInterval.Stop + 1);

                return(Create(baseVariant, baseInterval, svType, posContigAndInterval,
                              Winner.Create(svType, baseInterval, bins), new List <OverlapAnnotation>(),
                              WittyerSample.CreateOverall(baseVariant, sample, svType == WittyerVariantType.CopyNumberReference),
                              endContigAndInterval));
            }
Example #2
0
        public void GenerateWhatAndWhyWorksWithCnSample(bool isAlleleMatch, uint posStart, uint posEnd, uint endStart, uint endEnd,
                                                        bool isGtMatch, uint cn, MatchEnum matchResult, FailedReason reasonResult)
        {
            var originalVariant = GetOriginalCnvGtVariant();
            var otherVariant    =
                SetupBasicVariant(isAlleleMatch ? PrimaryContigAndInterval : PrimaryFailedContigAndInterval);

            otherVariant.SetupGet(v => v.PosInterval).Returns(ContigAndInterval.Create(PrimaryContig, posStart, posEnd));
            otherVariant.SetupGet(v => v.EndInterval).Returns(ContigAndInterval.Create(PrimaryContig, endStart, endEnd));
            var otherSample = new Mock <IWittyerGenotypedCopyNumberSample>();

            var gt = new Mock <IGenotypeInfo>();

            if (originalVariant.Sample is IWittyerGenotypedSample gtSample)
            {
                gt.Setup(g => g.Equals(gtSample.Gt)).Returns(isGtMatch);
            }

            otherSample.SetupGet(s => s.Gt).Returns(gt.Object);
            otherSample.SetupGet(s => s.Cn).Returns(cn);

            otherVariant.SetupGet(v => v.Sample).Returns(otherSample.Object);

            var actual = OverlappingUtils.GenerateWhatAndWhy(otherVariant.Object, new List <FailedReason>(),
                                                             originalVariant, OverlappingUtils.IsVariantAlleleMatch, false);

            Assert.Equal((matchResult, reasonResult), actual);
        }
Example #3
0
        private static GenomeIntervalTree <IContigAndInterval> CreateGenomeIntervalTree(
            [NotNull] IEnumerable <IContigAndInterval> contigIntervals)
        {
            var dictionary = new Dictionary <IContigInfo, MergedIntervalTree <uint> >();
            var listOrder  = new List <IContigInfo>();

            foreach (var contigInterval in contigIntervals)
            {
                if (!dictionary.TryGetValue(contigInterval.Contig, out var tree))
                {
                    tree = MergedIntervalTree <uint> .Create(null);

                    listOrder.Add(contigInterval.Contig);
                    dictionary.Add(contigInterval.Contig, tree);
                }
                tree.Add(contigInterval);
            }

            var ret = GenomeIntervalTree <IContigAndInterval> .Create();

            foreach (var contig in listOrder)
            {
                ret.AddRange(dictionary[contig]
                             .Select(i => i as IContigAndInterval ?? ContigAndInterval.Create(contig, i.Start, i.Stop)));
            }

            return(ret);
        }
        public static void WittyerVariantIntervalCorrect([NotNull] string variant, uint start, uint end,
                                                         uint posStart, uint posEnd, uint endStart, uint endEnd)
        {
            const string sampleName = "tumor";
            var          vcfVariant = VcfVariant.TryParse(variant,
                                                          VcfVariantParserSettings.Create(ImmutableList.Create("normal", sampleName), GenomeAssembly.Hg38))
                                      .GetOrThrowDebug();

            var _ = WittyerType.ParseFromVariant(vcfVariant, false, sampleName, out var type);

            if (type == null)
            {
                throw new NotSupportedException("This test does not handle svType null");
            }
            var wittyerVariant = WittyerVariantInternal
                                 .Create(vcfVariant, vcfVariant.Samples[sampleName], type, Bins, PercentDistance, BasepairDistance);

            var expectedStart = ContigAndInterval.Create(vcfVariant.Contig, start, end);
            var expectedPos   = BedInterval.Create(posStart, posEnd);
            var expectedEnd   = BedInterval.Create(endStart, endEnd);

            MultiAssert.Equal(expectedStart, wittyerVariant);
            MultiAssert.Equal(expectedPos, wittyerVariant.CiPosInterval);
            MultiAssert.Equal(expectedEnd, wittyerVariant.CiEndInterval);
            MultiAssert.AssertAll();
        }
        public void CalculateBndBorderDistanceWorks([NotNull] string chr, uint position, [NotNull] string otherChr, uint otherPos,
                                                    int ciStart, int ciEnd, double percentDistance, uint basepairDistance, uint borderStart, uint borderEnd)
        {
            var thisPos       = ContigAndPosition.Create(ContigInfo.Create(chr), position);
            var otherPosition = ContigAndPosition.Create(ContigInfo.Create(otherChr), otherPos);
            var ci            = new InclusiveInterval <int>(ciStart, ciEnd);

            var actualCi   = thisPos.CalculateBndBorderInterval(otherPosition, ci, percentDistance, basepairDistance);
            var expectedCi = ContigAndInterval.Create(ContigInfo.Create(chr), borderStart, borderEnd);

            Assert.Equal(expectedCi, actualCi);
        }
Example #6
0
        private static IWittyerVariant GetOriginalCnvGtVariant()
        {
            var variant = SetupBasicVariant(PrimaryContigAndInterval);

            variant.SetupGet(v => v.PosInterval).Returns(ContigAndInterval.Create(PrimaryContig, 1001, 1500));
            variant.SetupGet(v => v.EndInterval).Returns(ContigAndInterval.Create(PrimaryContig, 5001, 5601));

            var sample = new Mock <IWittyerGenotypedCopyNumberSample>();

            sample.SetupGet(s => s.Cn).Returns(3);

            sample.SetupGet(s => s.Gt).Returns(new Mock <IGenotypeInfo>().Object);
            variant.SetupGet(v => v.Sample).Returns(sample.Object);

            return(variant.Object);
        }
Example #7
0
        internal static IContigAndInterval CalculateBndBorderInterval([NotNull] this IContigAndPosition position,
                                                                      [NotNull] IContigAndPosition otherPosition,
                                                                      InclusiveInterval <int> confidentInterval,
                                                                      double percentageDistance, uint basepairDistance)
        {
            //inter-chromosome breakend
            var interval = position.Position.CalculateBasePairDistance(confidentInterval, basepairDistance);

            //intra-chromosome breakend
            if (position.Contig.Equals(otherPosition.Contig) && position.Position != otherPosition.Position) //Insertion does not count PD as well
            {
                interval = position.Position.CalculateBorderInterval(
                    new ClosedOpenInterval <uint>(Math.Min(position.Position, otherPosition.Position),
                                                  Math.Max(position.Position, otherPosition.Position)), confidentInterval,
                    percentageDistance, basepairDistance);
            }

            return(ContigAndInterval.Create(position.Contig, interval.Start, interval.Stop));
        }
        public static void WittyerIntraBndWorkCorrectly()
        {
            var vcfSettings =
                VcfVariantParserSettings.Create(ImmutableList.Create("proband", "father"), GenomeAssembly.Grch37);
            var bnd1 = VcfVariant.TryParse(GenotypedIntraBnd, vcfSettings).GetOrThrowDebug();

            var bnd2       = VcfVariant.TryParse(GenotypedIntraBndPair, vcfSettings).GetOrThrowDebug();
            var wittyerBnd = WittyerBndInternal
                             .Create(bnd2, bnd2.Samples["father"], WittyerType.IntraChromosomeBreakend, Bins, BasepairDistance,
                                     PercentDistance, bnd1);

            var distance            = Math.Round(Math.Abs(bnd1.Position - bnd2.Position) * PercentDistance);
            var expectedEndInterval = ContigAndInterval.Create(wittyerBnd.Contig, bnd1.Position - (uint)distance - 1,
                                                               bnd1.Position + (uint)distance);

            MultiAssert.Equal(expectedEndInterval, wittyerBnd.EndInterval);
            MultiAssert.Equal(10000U, wittyerBnd.Win.End);
            MultiAssert.AssertAll();

            Assert.IsType <WittyerGenotypedSample>(wittyerBnd.Sample);
        }
        public static void WittyerBndCreateCorrectly()
        {
            var vcfSettings =
                VcfVariantParserSettings.Create(ImmutableList.Create("proband", "father"), GenomeAssembly.Grch37);
            var bnd1 = VcfVariant.TryParse(GenotypedBnd, vcfSettings).GetOrThrowDebug();

            var bnd2       = VcfVariant.TryParse(GenotypedBndPair, vcfSettings).GetOrThrowDebug();
            var wittyerBnd = WittyerBndInternal
                             .Create(bnd2, bnd2.Samples["father"], WittyerType.TranslocationBreakend, Bins,
                                     BasepairDistance, PercentDistance, bnd1);

            var expectedContig      = ContigInfo.Create("1");
            var expectedEndInterval = ContigAndInterval.Create(ContigInfo.Create("4"), 191034451, 191035452);

            MultiAssert.Equal(expectedContig, wittyerBnd.Contig);
            MultiAssert.Equal(expectedEndInterval, wittyerBnd.EndInterval);
            MultiAssert.Equal(230675U, wittyerBnd.Start);
            MultiAssert.Equal(231676U, wittyerBnd.Stop);
            MultiAssert.Equal(WittyerConstants.StartingBin, wittyerBnd.Win.Start);
            MultiAssert.Equal(null, wittyerBnd.Win.End);
            MultiAssert.AssertAll();
        }
        internal static IWittyerBnd Create([NotNull] IVcfVariant first, [CanBeNull] IVcfSample originalSample,
                                           [NotNull] WittyerType svType, [NotNull] IReadOnlyList <uint> bins, uint bpd, double?percentageDistance,
                                           [NotNull] IVcfVariant second)
        {
            if (!ReferenceEquals(first, second))
            {
                (first, second) = FindBndEntriesOrder(in first, in second);
            }

            var ciPosInterval = first.Position.ConvertPositionToCiInterval(first, WittyerConstants.Cipos);
            var ciEndInterval = ReferenceEquals(first, second)
                ? ciPosInterval // same variant means same intervals.
                : second.Position.ConvertPositionToCiInterval(second, WittyerConstants.Cipos);

            IContigAndInterval posInterval, endInterval;

            if (ReferenceEquals(first, second)) // insertions need trimming and stuff.
            {
                var trimmed = first.TryNormalizeVariant(VariantNormalizer.TrimCommonBases, 0).GetOrThrow();
                var tuple   = (bpd, bpd);
                var(posStart, posStop) = trimmed.Position.ConvertPositionToCiInterval(tuple);
                WittyerUtils.GetBetterInterval(ciPosInterval, ref posStart, ref posStop);
                posInterval = endInterval = ContigAndInterval.Create(first.Contig, posStart, posStop);
            }
            else
            {
                (posInterval, endInterval) = WittyerUtils.GetPosAndEndInterval(first.Contig,
                                                                               svType == WittyerType.IntraChromosomeBreakend ? percentageDistance : null, bpd,
                                                                               ciPosInterval, first.Position, ciEndInterval, second.Position, second.Contig);
            }

            var winner = GetWinner();

            var sample = WittyerSample.CreateFromVariant(first, originalSample, false);

            return(new WittyerBndInternal(svType, first, posInterval, ciPosInterval,
                                          second, endInterval, ciEndInterval, winner, sample));

            (IVcfVariant first, IVcfVariant second) FindBndEntriesOrder(in IVcfVariant variantA,
                                                                        in IVcfVariant variantB)
            => ContigAndPositionComparer.Default.Compare(variantA, variantB) > 0
                    ? (variantB, variantA)
                    : (variantA, variantB);

            Winner GetWinner()
            {
                if (svType == WittyerType.TranslocationBreakend)
                {
                    return(Winner.Create(svType));
                }


                IInterval <uint> bedInterval;

                if (svType == WittyerType.Insertion)
                {
                    bedInterval = GetInsertionInterval(first);
                }
                else
                {
                    var start = first.Position;
                    if (start > 0)
                    {
                        start--;
                    }
                    bedInterval = BedInterval.Create(start, second.Position);
                }

                return(Winner.Create(svType, bedInterval, bins));
            }
        }
Example #11
0
        public void CnvWorksWithSimpleCounting()
        {
            if (MiscUtils.IsRunningAnyLinux)
            {
                return;                              // currently failing on linux :(
            }
            var outputDirectory = Path.GetRandomFileName().ToDirectoryInfo();
            var wittyerSettings = WittyerSettings.Create(outputDirectory, CnvTruth, CnvQuery,
                                                         ImmutableList <ISamplePair> .Empty, EvaluationMode.SimpleCounting, InputSpecs);

            var actualStats = MainLauncher
                              .GenerateJson(wittyerSettings, MainLauncher.GenerateResults(wittyerSettings).EnumerateSuccesses(),
                                            EmptyCmd).GetOrThrow().PerSampleStats.First();
            //var str = JsonConvert.SerializeObject(actualStats, Formatting.Indented);
            var jsonText      = File.ReadAllText(CnvJsonSc.FullName);
            var expectedStats = JsonConvert.DeserializeObject <GeneralStats>(jsonText)
                                .PerSampleStats.First();

            var expectedOverall           = expectedStats.OverallStats;
            var actualOverall             = actualStats.OverallStats;
            var expectedOverallEventStats = expectedOverall.Single(x => x.StatsType.Equals(StatsType.Event));
            var actualOverallEventStats   = actualOverall.Single(x => x.StatsType.Equals(StatsType.Event));

            MultiAssert.Equal(expectedOverallEventStats.QueryFpCount, actualOverallEventStats.QueryFpCount);
            MultiAssert.Equal(expectedOverallEventStats.QueryTpCount, actualOverallEventStats.QueryTpCount);
            MultiAssert.Equal(expectedOverallEventStats.QueryTotalCount, actualOverallEventStats.QueryTotalCount);
            MultiAssert.Equal(expectedOverallEventStats.TruthTpCount, actualOverallEventStats.TruthTpCount);
            MultiAssert.Equal(expectedOverallEventStats.TruthFnCount, actualOverallEventStats.TruthFnCount);
            MultiAssert.Equal(expectedOverallEventStats.TruthTotalCount, actualOverallEventStats.TruthTotalCount);

            var expectedCnvTypeOverallStats = expectedStats.DetailedStats
                                              .Single(x => x.VariantType == WittyerType.CopyNumberGain.Name).OverallStats.Concat(expectedStats
                                                                                                                                 .DetailedStats.Single(x => x.VariantType == WittyerType.CopyNumberLoss.Name).OverallStats)
                                              .ToReadOnlyList();
            var actualCnvTypeOverallStats = actualStats.DetailedStats
                                            .Single(x => x.VariantType == WittyerType.CopyNumberGain.Name).OverallStats.Concat(actualStats
                                                                                                                               .DetailedStats.Single(x => x.VariantType == WittyerType.CopyNumberLoss.Name).OverallStats)
                                            .ToReadOnlyList();
            var expectedOverallCnvEventStats = expectedCnvTypeOverallStats
                                               .Where(x => x.StatsType.Equals(StatsType.Event))
                                               .Aggregate(BasicJsonStats.Create(StatsType.Event, 0, 0, 0, 0), (acc, target) => acc + target);
            var actualOverallCnvEventStats = actualCnvTypeOverallStats.Where(x => x.StatsType.Equals(StatsType.Event))
                                             .Aggregate(BasicJsonStats.Create(StatsType.Event, 0, 0, 0, 0), (acc, target) => acc + target);

            MultiAssert.Equal(expectedOverallCnvEventStats.QueryFpCount, actualOverallCnvEventStats.QueryFpCount);
            MultiAssert.Equal(expectedOverallCnvEventStats.QueryTpCount, actualOverallCnvEventStats.QueryTpCount);
            MultiAssert.Equal(expectedOverallCnvEventStats.QueryTotalCount, actualOverallCnvEventStats.QueryTotalCount);
            MultiAssert.Equal(expectedOverallCnvEventStats.TruthTpCount, actualOverallCnvEventStats.TruthTpCount);
            MultiAssert.Equal(expectedOverallCnvEventStats.TruthFnCount, actualOverallCnvEventStats.TruthFnCount);
            MultiAssert.Equal(expectedOverallCnvEventStats.TruthTotalCount, actualOverallCnvEventStats.TruthTotalCount);

            var expectedOverallCnvBaseStats = expectedCnvTypeOverallStats.Where(x => x.StatsType.Equals(StatsType.Base))
                                              .Aggregate(BasicJsonStats.Create(StatsType.Base, 0, 0, 0, 0), (acc, target) => acc + target);
            var actualOverallCnvBaseStats = actualCnvTypeOverallStats.Where(x => x.StatsType.Equals(StatsType.Base))
                                            .Aggregate(BasicJsonStats.Create(StatsType.Base, 0, 0, 0, 0), (acc, target) => acc + target);

            MultiAssert.Equal(expectedOverallCnvBaseStats.QueryFpCount, actualOverallCnvBaseStats.QueryFpCount);
            MultiAssert.Equal(expectedOverallCnvBaseStats.QueryTpCount, actualOverallCnvBaseStats.QueryTpCount);
            MultiAssert.Equal(expectedOverallCnvBaseStats.QueryTotalCount, actualOverallCnvBaseStats.QueryTotalCount);
            MultiAssert.Equal(expectedOverallCnvBaseStats.TruthTpCount, actualOverallCnvBaseStats.TruthTpCount);
            MultiAssert.Equal(expectedOverallCnvBaseStats.TruthFnCount, actualOverallCnvBaseStats.TruthFnCount);
            MultiAssert.Equal(expectedOverallCnvBaseStats.TruthTotalCount, actualOverallCnvBaseStats.TruthTotalCount);

            #region test CNVs w/o Refs

            // ReSharper disable ConditionIsAlwaysTrueOrFalse
            var refs = false;
            var(expectedOrthogonalTruthBaseTotal, expectedOrthogonalTruthEventTotal) = GetTotalCnvs(CnvTruth, refs);
            var(expectedOrthogonalQueryBaseTotal, expectedOrthogonalQueryEventTotal) = GetTotalCnvs(CnvQuery, refs);

            var actualCnvBaseStatsBinned   = GetCnvStats(actualStats, refs);
            var expectedCnvBaseStatsBinned = GetCnvStats(expectedStats, refs);

            var(actualTruthBaseTotal, actualQueryBaseTotal, actualTruthEventTotal, actualQueryEventTotal) =
                GetActualTotalStatsFromBins(expectedCnvBaseStatsBinned, actualCnvBaseStatsBinned, refs);

            // expected truth is off by 6, five of which is because of overlap. Last off by 1 is unexplained.  Not sure why, but there could be a hidden bug somewhere.
            MultiAssert.Equal(expectedOrthogonalTruthBaseTotal, actualTruthBaseTotal - 6);
            MultiAssert.Equal(expectedOrthogonalQueryBaseTotal, actualQueryBaseTotal);

            MultiAssert.Equal(expectedOrthogonalTruthEventTotal, actualTruthEventTotal);
            MultiAssert.Equal(expectedOrthogonalQueryEventTotal, actualQueryEventTotal);

            MultiAssert.Equal(expectedOverallCnvBaseStats.TruthTotalCount, actualTruthBaseTotal - 5);
            MultiAssert.Equal(expectedOverallCnvBaseStats.QueryTotalCount, actualQueryBaseTotal);

            MultiAssert.Equal(expectedOrthogonalTruthBaseTotal, actualOverallCnvBaseStats.TruthTotalCount - 1);
            MultiAssert.Equal(expectedOrthogonalQueryBaseTotal, actualOverallCnvBaseStats.QueryTotalCount);

            #endregion

            #region test CNVs w/ Refs

            refs = true;
            (expectedOrthogonalTruthBaseTotal, expectedOrthogonalTruthEventTotal) = GetTotalCnvs(CnvTruth, refs);
            (expectedOrthogonalQueryBaseTotal, expectedOrthogonalQueryEventTotal) = GetTotalCnvs(CnvQuery, refs);

            actualCnvBaseStatsBinned   = GetCnvStats(actualStats, refs);
            expectedCnvBaseStatsBinned = GetCnvStats(expectedStats, refs);

            (actualTruthBaseTotal, actualQueryBaseTotal, actualTruthEventTotal, actualQueryEventTotal) =
                GetActualTotalStatsFromBins(expectedCnvBaseStatsBinned, actualCnvBaseStatsBinned, refs);
            // ReSharper restore ConditionIsAlwaysTrueOrFalse

            // expected truth is off by 6, five of which is because of overlap. Last off by 1 is unexplained.  Not sure why, but there could be a hidden bug somewhere.
            MultiAssert.Equal(expectedOrthogonalTruthBaseTotal, actualTruthBaseTotal - 6);
            MultiAssert.Equal(expectedOrthogonalQueryBaseTotal, actualQueryBaseTotal);

            MultiAssert.Equal(expectedOverall.Single(j => j.StatsType == StatsType.Base).TruthTotalCount,
                              actualTruthBaseTotal - 6);
            MultiAssert.Equal(expectedOverall.Single(j => j.StatsType == StatsType.Base).QueryTotalCount,
                              actualQueryBaseTotal);

            MultiAssert.Equal(expectedOrthogonalTruthEventTotal, actualTruthEventTotal);
            MultiAssert.Equal(expectedOrthogonalQueryEventTotal, actualQueryEventTotal);

            MultiAssert.Equal(expectedOrthogonalTruthBaseTotal,
                              actualOverall.Single(s => s.StatsType == StatsType.Base).TruthTotalCount);
            MultiAssert.Equal(expectedOrthogonalQueryBaseTotal,
                              actualOverall.Single(s => s.StatsType == StatsType.Base).QueryTotalCount);

            #endregion

            MultiAssert.AssertAll();

            Dictionary <string, Dictionary <StatsType, BasicJsonStats> > GetCnvStats(SampleStats sampleStats,
                                                                                     bool includeRef)
            => sampleStats.DetailedStats
            .Where(x => x.VariantType.Equals(WittyerType.CopyNumberGain.Name) ||
                   x.VariantType.Equals(WittyerType.CopyNumberLoss.Name) ||
                   includeRef && x.VariantType.Equals(WittyerType.CopyNumberReference.Name))
            .SelectMany(v => v.PerBinStats)
            .GroupBy(s => s.Bin).ToDictionary(binGroups => binGroups.Key,
                                              binGroups => binGroups.SelectMany(binStats => binStats.Stats).GroupBy(s => s.StatsType)
                                              .ToDictionary(statsGroup => statsGroup.Key,
                                                            statsGroup => statsGroup.Aggregate(BasicJsonStats.Create(statsGroup.Key, 0, 0, 0, 0),
                                                                                               (acc, stat) => acc + stat)));

            (ulong totalLength, uint numEvents) GetTotalCnvs(FileInfo vcf, bool includeRefs)
            {
                var trees = new ConcurrentDictionary <IContigInfo, MergedIntervalTree <uint> >();

                // DO NOT delete: the line below are left there case we want to test without overlapping variants for test tweaking etc. i.e. it's debug code.
                // IContigAndInterval lastInterval = null;
                var numEvents = 0U;

                foreach (var variant in VcfReader.TryCreate(vcf).GetOrThrow().Select(v => v.GetOrThrow()))
                {
                    if (!IsCountedCnv(variant))
                    {
                        continue;
                    }
                    numEvents++;
                    var tree = trees.GetOrAdd(variant.Contig, _ => MergedIntervalTree.Create <uint>());

                    IContigAndInterval interval;
                    var start = variant.Position;
                    if (variant.Info.TryGetValue(VcfConstants.EndTagKey, out var end))
                    {
                        if (uint.TryParse(end, out var endVal))
                        {
                            interval = GetInterval(variant.Contig, start, endVal);
                        }
                        else
                        {
                            throw new ParserException($"couldn't parse {end} into END!");
                        }
                    }
                    else if (variant.Info.TryGetValue(VcfConstants.SvLenKey, out var svLen))
                    {
                        if (int.TryParse(svLen, out var len))
                        {
                            interval = len < 0
                                ? GetInterval(variant.Contig, start - (uint)-len, start)
                                : GetInterval(variant.Contig, start, start + (uint)len);
                        }
                        else
                        {
                            throw new ParserException($"couldn't parse {svLen} into svLen!");
                        }
                    }
                    else
                    {
                        throw new NotImplementedException(
                                  "Parsing using anything but svlen is not supported, should probably add it.");
                    }

                    tree.Add(interval);

                    // DO NOT delete: the line below are left there case we want to test without overlapping variants for test tweaking etc. i.e. it's debug code.
                    //lastInterval = interval;
                }

                return(trees.GetTotalLength(), numEvents);

                IContigAndInterval GetInterval(IContigInfo contig, uint position, uint end)
                {
                    var interval = ContigAndInterval.Create(contig, position, end);

                    return(interval);

                    // DO NOT delete: the remaining lines below are left there case we want to test without overlapping variants for test tweaking etc. i.e. it's debug code.
                    //if (lastInterval == null || !interval.Contig.Equals(lastInterval.Contig)) return interval;

                    //// adjust for possible overlaps between bins. (see https://jira.illumina.com/browse/WIT-84)
                    //var overlap = interval.TryGetOverlap(lastInterval).Select(o => o.GetLength()).GetOrDefault();
                    //if (overlap > 0)
                    //    interval = ContigAndInterval.Create(interval.Contig, interval.Start + overlap,
                    //        interval.Stop + overlap);

                    //return interval;
                }

                bool IsCountedCnv(IVcfVariant variant)
                {
                    if (variant.Filters.SingleOrDefault() != VcfConstants.PassFilter)
                    {
                        // if not single or not PASS return false
                        return(false);
                    }
                    var isRef = variant.Alts.SingleOrDefault() == VcfConstants.MissingValueString;

                    if (isRef)
                    {
                        return(includeRefs);
                    }

                    if (variant.Samples.Count == 0)
                    {
                        return(false);
                    }

                    var hasCn = variant.Samples[0].SampleDictionary
                                .TryGetValue(VcfConstants.CnSampleFieldKey, out var cn);

                    var hasGt = variant.Samples[0].SampleDictionary.TryGetValue(VcfConstants.GenotypeKey, out var gt);

                    if (!hasCn)
                    {
                        return(includeRefs && // no cn means only true if we include Refs
                               hasGt && gt.Split(VcfConstants.GtPhasedValueDelimiter[0],
                                                 VcfConstants.GtUnphasedValueDelimiter[0])
                               .All(x => x == "0"));
                    }

                    if (!variant.Info.TryGetValue(VcfConstants.SvTypeKey, out var svType) ||
                        !WittyerConstants.BaseLevelStatsTypeStrings.Contains(svType))
                    {
                        return(false);
                    }
                    if (!int.TryParse(cn, out var ploidy))
                    {
                        return(false);
                    }

                    isRef = (hasGt
                                ? gt.Split(VcfConstants.GtPhasedValueDelimiter[0],
                                           VcfConstants.GtUnphasedValueDelimiter[0]).Length
                                : 2) == ploidy;
                    return(!isRef || includeRefs);
                }
            }

            (ulong, ulong, ulong, ulong) GetActualTotalStatsFromBins(
                Dictionary <string, Dictionary <StatsType, BasicJsonStats> > expectedBinned,
                Dictionary <string, Dictionary <StatsType, BasicJsonStats> > actualBinned, bool includeRefs)
            {
                var actualTruthBase  = 0UL;
                var actualQueryBase  = 0UL;
                var actualTruthEvent = 0UL;
                var actualQueryEvent = 0UL;

                foreach (var(bin, binStats) in expectedBinned)
                {
                    foreach (var(type, expectedCnvStats) in binStats)
                    {
                        var actualCnvStats = actualBinned[bin][type];
                        if (type == StatsType.Base)
                        {
                            actualTruthBase += actualCnvStats.TruthTotalCount;
                            actualQueryBase += actualCnvStats.QueryTotalCount;
                        }
                        else
                        {
                            actualTruthEvent += actualCnvStats.TruthTotalCount;
                            actualQueryEvent += actualCnvStats.QueryTotalCount;
                        }

                        if (!expectedCnvStats.Equals(actualCnvStats))
                        {
                            MultiAssert.Equal(expectedCnvStats, actualCnvStats);
                            MultiAssert.Equal("Expected ", includeRefs.ToString());
                        }
                    }
                }

                return(actualTruthBase, actualQueryBase, actualTruthEvent, actualQueryEvent);
            }
        }