Exemple #1
0
        public IEnumerable <TransitionDocNode> GetTransitions(SrmSettings settings,
                                                              TransitionGroupDocNode groupDocNode,
                                                              ExplicitMods mods,
                                                              double precursorMz,
                                                              IsotopeDistInfo isotopeDist,
                                                              SpectrumHeaderInfo libInfo,
                                                              IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks,
                                                              bool useFilter)
        {
            Assume.IsTrue(ReferenceEquals(groupDocNode.TransitionGroup, this));
            // Get necessary mass calculators and masses
            var calcFilterPre = settings.GetPrecursorCalc(IsotopeLabelType.light, mods);
            var calcFilter    = settings.GetFragmentCalc(IsotopeLabelType.light, mods);
            var calcPredict   = settings.GetFragmentCalc(LabelType, mods);

            string sequence = Peptide.Sequence;

            // Save the true precursor m/z for TranstionSettings.Accept() now that all isotope types are
            // checked.  This is more correct than just using the light precursor m/z for precursor window
            // exclusion.
            double precursorMzAccept = precursorMz;

            if (!ReferenceEquals(calcFilter, calcPredict))
            {
                // Get the normal precursor m/z for filtering, so that light and heavy ion picks will match.
                precursorMz = IsCustomIon ?
                              BioMassCalc.CalculateIonMz(calcFilterPre.GetPrecursorMass(groupDocNode.CustomIon), groupDocNode.TransitionGroup.PrecursorCharge) :
                              SequenceMassCalc.GetMZ(calcFilterPre.GetPrecursorMass(sequence), groupDocNode.TransitionGroup.PrecursorCharge);
            }
            if (!IsAvoidMismatchedIsotopeTransitions)
            {
                precursorMzAccept = precursorMz;
            }

            var      tranSettings      = settings.TransitionSettings;
            var      filter            = tranSettings.Filter;
            var      charges           = filter.ProductCharges;
            var      startFinder       = filter.FragmentRangeFirst;
            var      endFinder         = filter.FragmentRangeLast;
            double   precursorMzWindow = filter.PrecursorMzWindow;
            var      types             = filter.IonTypes;
            MassType massType          = tranSettings.Prediction.FragmentMassType;
            int      minMz             = tranSettings.Instrument.GetMinMz(precursorMzAccept);
            int      maxMz             = tranSettings.Instrument.MaxMz;

            var pepMods         = settings.PeptideSettings.Modifications;
            var potentialLosses = CalcPotentialLosses(sequence, pepMods, mods, massType);

            // A start m/z will need to be calculated if the start fragment
            // finder uses m/z and their are losses to consider.  If the filter
            // is set to only consider fragments with m/z greater than the
            // precursor, the code below needs to also prevent loss fragments
            // from being under that m/z.
            double startMz = 0;

            // Get library settings
            var pick = tranSettings.Libraries.Pick;

            if (!useFilter)
            {
                pick = TransitionLibraryPick.all;
                var listAll = Transition.ALL_CHARGES.ToList();
                listAll.AddRange(charges.Where(c => !Transition.ALL_CHARGES.Contains(c)));
                listAll.Sort();
                charges = listAll.ToArray();
                types   = Transition.ALL_TYPES;
            }
            // If there are no libraries or no library information, then
            // picking cannot use library information
            else if (!settings.PeptideSettings.Libraries.HasLibraries || libInfo == null)
            {
                pick = TransitionLibraryPick.none;
            }

            // If filtering without library picking
            if (potentialLosses != null)
            {
                if (pick == TransitionLibraryPick.none)
                {
                    // Only include loss combinations where all losses are included always
                    potentialLosses = potentialLosses.Where(losses =>
                                                            losses.All(loss => loss.TransitionLoss.Loss.Inclusion == LossInclusion.Always)).ToArray();
                }
                else if (useFilter)
                {
                    // Exclude all losses which should never be included by default
                    potentialLosses = potentialLosses.Where(losses =>
                                                            losses.All(loss => loss.TransitionLoss.Loss.Inclusion != LossInclusion.Never)).ToArray();
                }
                if (!potentialLosses.Any())
                {
                    potentialLosses = null;
                }
            }

            // Return precursor ions
            if (!useFilter || types.Contains(IonType.precursor))
            {
                bool libraryFilter = (pick == TransitionLibraryPick.all || pick == TransitionLibraryPick.filter);
                foreach (var nodeTran in GetPrecursorTransitions(settings, mods, calcFilterPre, calcPredict,
                                                                 precursorMz, isotopeDist, potentialLosses, transitionRanks, libraryFilter, useFilter))
                {
                    if (minMz <= nodeTran.Mz && nodeTran.Mz <= maxMz)
                    {
                        yield return(nodeTran);
                    }
                }
            }

            // Return special ions from settings, if this is a peptide
            if (!IsCustomIon)
            {
                // This is a peptide, but it may have custom transitions (reporter ions), check those
                foreach (var measuredIon in tranSettings.Filter.MeasuredIons.Where(m => m.IsCustom))
                {
                    if (useFilter && measuredIon.IsOptional)
                    {
                        continue;
                    }
                    var    tran     = new Transition(this, measuredIon.Charge, null, measuredIon.CustomIon);
                    double mass     = settings.GetFragmentMass(IsotopeLabelType.light, null, tran, null);
                    var    nodeTran = new TransitionDocNode(tran, null, mass, null, null);
                    if (minMz <= nodeTran.Mz && nodeTran.Mz <= maxMz)
                    {
                        yield return(nodeTran);
                    }
                }
            }

            // For small molecules we can't generate new nodes, so just mz filter those we have
            foreach (var nodeTran in groupDocNode.Transitions.Where(tran => tran.Transition.IsNonPrecursorNonReporterCustomIon()))
            {
                if (minMz <= nodeTran.Mz && nodeTran.Mz <= maxMz)
                {
                    yield return(nodeTran);
                }
            }

            if (sequence == null) // Completely custom
            {
                yield break;
            }

            // If picking relies on library information
            if (useFilter && pick != TransitionLibraryPick.none)
            {
                // If it is not yet loaded, or nothing got ranked, return an empty enumeration
                if (!settings.PeptideSettings.Libraries.IsLoaded ||
                    (transitionRanks != null && transitionRanks.Count == 0))
                {
                    yield break;
                }
            }

            double[,] massesPredict = calcPredict.GetFragmentIonMasses(sequence);
            int len = massesPredict.GetLength(1);

            if (len == 0)
            {
                yield break;
            }

            double[,] massesFilter = massesPredict;
            if (!ReferenceEquals(calcFilter, calcPredict))
            {
                // Get the normal m/z values for filtering, so that light and heavy
                // ion picks will match.
                massesFilter = calcFilter.GetFragmentIonMasses(sequence);
            }

            // Get types other than this to make sure matches are possible for all types
            var listOtherTypes = new List <Tuple <TransitionGroupDocNode, IFragmentMassCalc> >();

            foreach (var labelType in settings.PeptideSettings.Modifications.GetModificationTypes())
            {
                if (Equals(labelType, LabelType))
                {
                    continue;
                }
                var calc = settings.GetFragmentCalc(labelType, mods);
                if (calc == null)
                {
                    continue;
                }
                var tranGroupOther = new TransitionGroup(Peptide, PrecursorCharge, labelType, false, DecoyMassShift);
                var nodeGroupOther = new TransitionGroupDocNode(tranGroupOther, Annotations.EMPTY, settings, mods,
                                                                libInfo, ExplicitTransitionGroupValues.EMPTY, null, new TransitionDocNode[0], false);

                listOtherTypes.Add(new Tuple <TransitionGroupDocNode, IFragmentMassCalc>(nodeGroupOther, calc));
            }

            // Loop over potential product ions picking transitions
            foreach (IonType type in types)
            {
                // Precursor type is handled above.
                if (type == IonType.precursor)
                {
                    continue;
                }

                foreach (int charge in charges)
                {
                    // Precursor charge can never be lower than product ion charge.
                    if (Math.Abs(PrecursorCharge) < Math.Abs(charge))
                    {
                        continue;
                    }

                    int start = 0, end = 0;
                    if (pick != TransitionLibraryPick.all)
                    {
                        start = startFinder.FindStartFragment(massesFilter, type, charge,
                                                              precursorMz, precursorMzWindow, out startMz);
                        end = endFinder.FindEndFragment(type, start, len);
                        if (Transition.IsCTerminal(type))
                        {
                            Helpers.Swap(ref start, ref end);
                        }
                    }

                    for (int i = 0; i < len; i++)
                    {
                        // Get the predicted m/z that would be used in the transition
                        double massH = massesPredict[(int)type, i];
                        foreach (var losses in CalcTransitionLosses(type, i, massType, potentialLosses))
                        {
                            double ionMz = SequenceMassCalc.GetMZ(Transition.CalcMass(massH, losses), charge);

                            // Make sure the fragment m/z value falls within the valid instrument range.
                            // CONSIDER: This means that a heavy transition might excede the instrument
                            //           range where a light one is accepted, leading to a disparity
                            //           between heavy and light transtions picked.
                            if (minMz > ionMz || ionMz > maxMz)
                            {
                                continue;
                            }

                            TransitionDocNode nodeTranReturn = null;
                            bool accept = true;
                            if (pick == TransitionLibraryPick.all || pick == TransitionLibraryPick.all_plus)
                            {
                                if (!useFilter)
                                {
                                    nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks);
                                    accept         = false;
                                }
                                else
                                {
                                    if (IsMatched(transitionRanks, ionMz, type, charge, losses))
                                    {
                                        nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks);
                                        accept         = false;
                                    }
                                    // If allowing library or filter, check the filter to decide whether to accept
                                    else if (pick == TransitionLibraryPick.all_plus &&
                                             tranSettings.Accept(sequence, precursorMzAccept, type, i, ionMz, start, end, startMz))
                                    {
                                        nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks);
                                    }
                                }
                            }
                            else if (tranSettings.Accept(sequence, precursorMzAccept, type, i, ionMz, start, end, startMz))
                            {
                                if (pick == TransitionLibraryPick.none)
                                {
                                    nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks);
                                }
                                else
                                {
                                    if (IsMatched(transitionRanks, ionMz, type, charge, losses))
                                    {
                                        nodeTranReturn = CreateTransitionNode(type, i, charge, massH, losses, transitionRanks);
                                    }
                                }
                            }
                            if (nodeTranReturn != null)
                            {
                                if (IsAvoidMismatchedIsotopeTransitions &&
                                    !OtherLabelTypesAllowed(settings, minMz, maxMz, start, end, startMz, accept,
                                                            groupDocNode, nodeTranReturn, listOtherTypes))
                                {
                                    continue;
                                }
                                Assume.IsTrue(minMz <= nodeTranReturn.Mz && nodeTranReturn.Mz <= maxMz);
                                yield return(nodeTranReturn);
                            }
                        }
                    }
                }
            }
        }
Exemple #2
0
        public static TransitionDocNode FromTransitionProto(AnnotationScrubber scrubber, SrmSettings settings,
                                                            TransitionGroup group, ExplicitMods mods, IsotopeDistInfo isotopeDist, ExplicitTransitionValues pre422ExplicitTransitionValues,
                                                            SkylineDocumentProto.Types.Transition transitionProto)
        {
            var         stringPool  = scrubber.StringPool;
            IonType     ionType     = DataValues.FromIonType(transitionProto.FragmentType);
            MeasuredIon measuredIon = null;

            if (transitionProto.MeasuredIonName != null)
            {
                measuredIon = settings.TransitionSettings.Filter.MeasuredIons.SingleOrDefault(
                    i => i.Name.Equals(transitionProto.MeasuredIonName.Value));
                if (measuredIon == null)
                {
                    throw new InvalidDataException(string.Format(Resources.TransitionInfo_ReadXmlAttributes_The_reporter_ion__0__was_not_found_in_the_transition_filter_settings_, transitionProto.MeasuredIonName));
                }
                ionType = IonType.custom;
            }
            bool           isCustom    = Transition.IsCustom(ionType, group);
            bool           isPrecursor = Transition.IsPrecursor(ionType);
            CustomMolecule customIon   = null;

            if (isCustom)
            {
                if (measuredIon != null)
                {
                    customIon = measuredIon.SettingsCustomIon;
                }
                else if (isPrecursor)
                {
                    customIon = group.CustomMolecule;
                }
                else
                {
                    var formula      = DataValues.FromOptional(transitionProto.Formula);
                    var moleculeID   = MoleculeAccessionNumbers.FromString(DataValues.FromOptional(transitionProto.MoleculeId)); // Tab separated list of InChiKey, CAS etc
                    var monoMassH    = DataValues.FromOptional(transitionProto.MonoMassH);
                    var averageMassH = DataValues.FromOptional(transitionProto.AverageMassH);
                    var monoMass     = DataValues.FromOptional(transitionProto.MonoMass) ?? monoMassH;
                    var averageMass  = DataValues.FromOptional(transitionProto.AverageMass) ?? averageMassH;
                    customIon = new CustomMolecule(formula,
                                                   new TypedMass(monoMass.Value, monoMassH.HasValue ? MassType.MonoisotopicMassH : MassType.Monoisotopic),
                                                   new TypedMass(averageMass.Value, averageMassH.HasValue ? MassType.AverageMassH : MassType.Average),
                                                   DataValues.FromOptional(transitionProto.CustomIonName), moleculeID);
                }
            }
            Transition transition;
            var        adductString = DataValues.FromOptional(transitionProto.Adduct);
            var        adduct       = string.IsNullOrEmpty(adductString)
                ? Adduct.FromChargeProtonated(transitionProto.Charge)
                : Adduct.FromStringAssumeChargeOnly(adductString);

            if (isCustom)
            {
                transition = new Transition(group, isPrecursor ? group.PrecursorAdduct :adduct, transitionProto.MassIndex, customIon, ionType);
            }
            else if (isPrecursor)
            {
                transition = new Transition(group, ionType, group.Peptide.Length - 1, transitionProto.MassIndex,
                                            group.PrecursorAdduct, DataValues.FromOptional(transitionProto.DecoyMassShift));
            }
            else
            {
                int offset = Transition.OrdinalToOffset(ionType, transitionProto.FragmentOrdinal,
                                                        group.Peptide.Length);
                transition = new Transition(group, ionType, offset, transitionProto.MassIndex, adduct, DataValues.FromOptional(transitionProto.DecoyMassShift));
            }
            var losses          = TransitionLosses.FromLossProtos(settings, transitionProto.Losses);
            var mass            = settings.GetFragmentMass(group, mods, transition, isotopeDist);
            var isotopeDistInfo = GetIsotopeDistInfo(transition, losses, isotopeDist);

            if (group.DecoyMassShift.HasValue && transitionProto.DecoyMassShift == null)
            {
                throw new InvalidDataException(Resources.SrmDocument_ReadTransitionXml_All_transitions_of_decoy_precursors_must_have_a_decoy_mass_shift);
            }

            TransitionLibInfo libInfo = null;

            if (transitionProto.LibInfo != null)
            {
                libInfo = new TransitionLibInfo(transitionProto.LibInfo.Rank, transitionProto.LibInfo.Intensity);
            }
            var annotations = scrubber.ScrubAnnotations(Annotations.FromProtoAnnotations(transitionProto.Annotations), AnnotationDef.AnnotationTarget.transition);
            var results     = TransitionChromInfo.FromProtoTransitionResults(scrubber, settings, transitionProto.Results);
            var explicitTransitionValues = pre422ExplicitTransitionValues ?? ExplicitTransitionValues.Create(
                DataValues.FromOptional(transitionProto.ExplicitCollisionEnergy),
                DataValues.FromOptional(transitionProto.ExplicitIonMobilityHighEnergyOffset),
                DataValues.FromOptional(transitionProto.ExplicitSLens),
                DataValues.FromOptional(transitionProto.ExplicitConeVoltage),
                DataValues.FromOptional(transitionProto.ExplicitDeclusteringPotential));

            return(new TransitionDocNode(transition, annotations, losses, mass, new TransitionQuantInfo(isotopeDistInfo, libInfo, !transitionProto.NotQuantitative), explicitTransitionValues, results));
        }