예제 #1
0
 private WittyerBndInternal([NotNull] WittyerType svType, [NotNull] IVcfVariant baseVariant,
                            [NotNull] IInterval <uint> posInterval, [NotNull] IInterval <uint> ciPosInterval,
                            [NotNull] IVcfVariant endOriginalVariant, [NotNull] IContigAndInterval endInterval,
                            [NotNull] IInterval <uint> ciEndInterval, [NotNull] Winner win, [NotNull] IWittyerSample sample)
 {
     Contig             = baseVariant.Contig;
     _posInterval       = posInterval;
     EndInterval        = endInterval;
     Sample             = sample;
     OriginalVariant    = baseVariant;
     EndOriginalVariant = endOriginalVariant;
     Win           = win;
     VariantType   = svType;
     CiPosInterval = ciPosInterval;
     CiEndInterval = ciEndInterval;
 }
예제 #2
0
 private WittyerVariantInternal([NotNull] WittyerType svType, [NotNull] IVcfVariant baseVariant,
                                [NotNull] IInterval <uint> baseInterval, [NotNull] Winner win,
                                [NotNull] IContigAndInterval posInterval, [NotNull] IInterval <uint> ciPosInterval,
                                [NotNull] IContigAndInterval endInterval, [NotNull] IInterval <uint> ciEndInterval,
                                [NotNull] IWittyerSample sample)
 {
     OriginalVariant = baseVariant;
     Contig          = baseVariant.Contig;
     VariantType     = svType;
     Win             = win;
     Sample          = sample;
     _baseInterval   = baseInterval;
     PosInterval     = posInterval;
     EndInterval     = endInterval;
     CiPosInterval   = ciPosInterval;
     CiEndInterval   = ciEndInterval;
 }
예제 #3
0
        internal static IWittyerVariant Create([NotNull] IVcfVariant baseVariant,
                                               [CanBeNull] IVcfSample sample, [NotNull] WittyerType svType,
                                               [NotNull] IReadOnlyList <uint> bins, [CanBeNull] double?percentageDistance,
                                               uint basepairDistance)
        {
            // originalInterval is needed to adjust CIPOS and CIEND against for PD/BPD, but it won't be used for actual reflen and binning.
            var baseInterval = baseVariant.ToBedInterval(true, out var originalEnd, out var sharedFirstBase);

            if (baseInterval == null)
            {
                throw new InvalidOperationException(
                          $"Expected failure of {nameof(WittyerUtils.ToBedInterval)} to throw, but didn't...");
            }

            // CI intervals are always based on the original POS/END
            var posStart = baseVariant.Position;

            if (sharedFirstBase)
            {
                posStart++;
            }
            var ciPosInterval = posStart.ConvertPositionToCiInterval(baseVariant, WittyerConstants.Cipos);
            var ciEndInterval = originalEnd.ConvertPositionToCiInterval(baseVariant, WittyerConstants.Ciend);

            var baseStart = sharedFirstBase
                ? baseInterval.Start
                : baseInterval.Start + 1; // not sharing first base (ref site or complex types,  etc) need adjustment

            // the pd/bpd intervals are based on the trimmed variant's coordinates.
            var(posInterval, endInterval) = WittyerUtils.GetPosAndEndInterval(baseVariant.Contig, percentageDistance,
                                                                              basepairDistance, ciPosInterval, baseStart, ciEndInterval, baseInterval.Stop);

            return(new WittyerVariantInternal(svType, baseVariant, baseInterval,
                                              Winner.Create(svType, baseInterval, bins),
                                              posInterval, ciPosInterval, endInterval, ciEndInterval,
                                              WittyerSample.CreateFromVariant(baseVariant, sample, svType == WittyerType.CopyNumberReference)));
        }
예제 #4
0
        public static FailedReason?ParseFromVariant([NotNull] IVcfVariant variant, bool isCrossTypeOn,
                                                    [CanBeNull] string sampleName, [CanBeNull] out WittyerType svType)
        {
            if (variant.IsRefSite() || IsRefCall(out var ploidy, out var cn, out var hasCn))
            {
                svType = CopyNumberReference;
                return(null);
            }

            var hasSvTypeKey = variant.Info.TryGetValue(VcfConstants.SvTypeKey, out var svTypeStr);

            if (!hasSvTypeKey)
            {
                // todo: maybe we can allow small variants, which would not have SVTYPE
                throw new InvalidDataException(
                          $"Following variant does not have {VcfConstants.SvTypeKey} info key:\n{variant}");
            }

            svType = null;
            if (svTypeStr == SvTypeStrings.TranslocationBreakend)
            {
                // breakends can be IntraChromosomeBreakend and TranslocationBreakend, so can't tell from SVTYPE.

                var mate = variant is IBreakEnd cast
                    ? cast.Mate
                    : SimpleBreakEnd.TryParse(variant.GetSingleAlt()).GetOrThrow();

                svType = variant.Contig.Equals(mate.Contig)
                    ? IntraChromosomeBreakend
                    : TranslocationBreakend;
                return(null);
            }

            if (!TryParseSvType(svTypeStr, out svType))
            {
                // Not BND because of check above, and if not parsable and not CNV, it's something we don't know.
                if (svTypeStr != SvTypeStrings.Cnv)
                {
                    throw new InvalidDataException($"Cannot recognize SVTYPE of {svTypeStr}");
                }
            }
            else if (!svType.HasBaseLevelStats)
            {
                // If INV or INS or whatever that doesn't need to look for CN, return.
                return(null);
            }

            if (!hasCn)
            {
                return(svType == null
                    ? FailedReason.CnvWithoutCn
                    : default(FailedReason?)); // DEL or DUP without CN
            }
            // At this point, it is CNV with CN or DEL/DUP with CN, which are also considered CNV
            if (cn == null)
            {
                // has CN, but can't parse.
                svType = null; // clear out SVTYPE=DEL/DUP
                return(FailedReason.UndeterminedCn);
            }

            svType = GetSvType(cn.Value);
            return(null);

            WittyerType GetSvType(int cnValue)
            => cnValue < ploidy
                    ? (isCrossTypeOn ? Deletion : CopyNumberLoss)
                    : (isCrossTypeOn ? Duplication : CopyNumberGain);

            bool IsRefCall(out int ploidyP, out int?cnP, out bool hasCnP)
            {
                ploidyP = 2;
                cnP     = null;
                hasCnP  = false;
                //if not refsite and no sample field, not a refcall
                if (variant.Samples.Count == 0)
                {
                    return(false);
                }

                var sample = sampleName == null ? variant.Samples[0] : variant.Samples[sampleName];

                hasCnP = sample.SampleDictionary.TryGetValue(VcfConstants.CnSampleFieldKey, out var cnString);
                var isGt = sample.SampleDictionary.TryGetValue(VcfConstants.GenotypeKey, out var gt);

                if (hasCnP && int.TryParse(cnString, out var i))
                {
                    cnP = i;
                }
                if (!isGt)
                {
                    return(hasCnP && cnString == "2");
                }

                //todo: refining how to deal with ploidy. Also here we don't deal with LOH. assuming CN = ploidy is ref
                var gtArray = gt.Split(VcfConstants.GtPhasedValueDelimiter[0],
                                       VcfConstants.GtUnphasedValueDelimiter[0]);

                ploidyP = gtArray.Length;
                return(cnP == null?gtArray.All(alleleIndex => alleleIndex == "0") : cnP.Value == ploidyP);
            }
        }
예제 #5
0
 internal static bool TryParseSvType(string svType, out WittyerType type)
 => AllSvTypesStrings.TryGetValue(svType, out type);
예제 #6
0
 public static bool TryParse(string name, [CanBeNull] out WittyerType type) =>
 AllTypesStrings.TryGetValue(name, out type);
예제 #7
0
        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));
            }
        }
예제 #8
0
 internal static IWittyerBnd CreateInsertion([NotNull] IVcfVariant first, [CanBeNull] IVcfSample originalSample,
                                             [NotNull] WittyerType svType, [NotNull] IReadOnlyList <uint> bins, uint bpd, double?pd)
 => Create(first, originalSample, svType, bins, bpd, pd, first);