예제 #1
0
        private static void AddOptimizationStepAreas(TransitionDocNode nodeTran, int iResult, TReg regression,
                                                     IDictionary <int, OptimizationStep <TReg> > optTotals)
        {
            var results = (nodeTran.HasResults ? nodeTran.Results[iResult] : null);

            // Skip the result set if it only has step 0, the predicted value. This happens
            // when someone mistakenly sets "Optimizing" on a data set that does not contain
            // optimization steps.
            if (results == null || results.All(c => c.OptimizationStep == 0 || c.IsEmpty))
            {
                return;
            }
            foreach (var chromInfo in results)
            {
                if (chromInfo.Area == 0)
                {
                    continue;
                }
                int step = chromInfo.OptimizationStep;
                OptimizationStep <TReg> optStep;
                if (!optTotals.TryGetValue(step, out optStep))
                {
                    optTotals.Add(step, optStep = new OptimizationStep <TReg>(regression, step));
                }
                optStep.AddArea(chromInfo.Area);
            }
        }
예제 #2
0
 private bool OtherLabelTypesAllowed(SrmSettings settings, double minMz, double maxMz, int start, int end, double startMz, bool accept,
                                     TransitionGroupDocNode nodeGroupMatching,
                                     TransitionDocNode nodeTran,
                                     IEnumerable <Tuple <TransitionGroupDocNode, IFragmentMassCalc> > listOtherTypes)
 {
     foreach (var otherType in listOtherTypes)
     {
         var nodeGroupOther   = otherType.Item1;
         var tranGroupOther   = nodeGroupOther.TransitionGroup;
         var nodeTranMatching = tranGroupOther.GetMatchingTransition(settings,
                                                                     nodeGroupMatching, nodeTran, otherType.Item2);
         if (minMz > nodeTranMatching.Mz || nodeTranMatching.Mz > maxMz)
         {
             return(false);
         }
         if (accept && !settings.TransitionSettings.Accept(Peptide.Sequence,
                                                           nodeGroupOther.PrecursorMz,
                                                           nodeTranMatching.Transition.IonType,
                                                           nodeTranMatching.Transition.CleavageOffset,
                                                           nodeTranMatching.Mz,
                                                           start,
                                                           end,
                                                           startMz))
         {
             return(false);
         }
     }
     return(true);
 }
예제 #3
0
        private TransitionDocNode GetMatchingTransition(SrmSettings settings,
                                                        TransitionGroupDocNode nodeGroupMatching,
                                                        TransitionDocNode nodeTran,
                                                        IFragmentMassCalc calc)
        {
            var transition     = nodeTran.Transition;
            var losses         = nodeTran.Losses;
            var libInfo        = nodeTran.LibInfo;
            int?decoyMassShift = transition.IsPrecursor() ? DecoyMassShift : transition.DecoyMassShift;
            var tranNew        = new Transition(this,
                                                transition.IonType,
                                                transition.CleavageOffset,
                                                transition.MassIndex,
                                                transition.Charge,
                                                decoyMassShift,
                                                transition.CustomIon ?? CustomIon); // Handle reporter ions as well as small molecules
            var    isotopeDist = nodeGroupMatching.IsotopeDist;
            double massH;

            if (tranNew.IsCustom())
            {
                massH = tranNew.CustomIon.GetMass(settings.TransitionSettings.Prediction.FragmentMassType);
            }
            else
            {
                massH = calc.GetFragmentMass(tranNew, isotopeDist);
            }
            var isotopeDistInfo  = TransitionDocNode.GetIsotopeDistInfo(tranNew, losses, isotopeDist);
            var nodeTranMatching = new TransitionDocNode(tranNew, losses, massH, isotopeDistInfo, libInfo);

            return(nodeTranMatching);
        }
예제 #4
0
 public TransitionLossKey(TransitionGroupDocNode parent, TransitionDocNode transition, TransitionLosses losses)
 {
     Transition = transition.Transition;
     Losses     = losses;
     if (Transition.IsCustom())
     {
         if (!string.IsNullOrEmpty(transition.PrimaryCustomIonEquivalenceKey))
         {
             CustomIonEquivalenceTestValue = transition.PrimaryCustomIonEquivalenceKey;
         }
         else if (!string.IsNullOrEmpty(transition.SecondaryCustomIonEquivalenceKey))
         {
             CustomIonEquivalenceTestValue = transition.SecondaryCustomIonEquivalenceKey;
         }
         else if (Transition.IsNonReporterCustomIon())
         {
             CustomIonEquivalenceTestValue = @"_mzSortIndex_" + parent.Children.IndexOf(transition);
         }
         else
         {
             CustomIonEquivalenceTestValue = null;
         }
     }
     else
     {
         CustomIonEquivalenceTestValue = null;
     }
 }
예제 #5
0
            public void Add(TransitionDocNode nodeTran, float abundance)
            {
                string ion     = nodeTran.FragmentIonName;
                float  current = !_abundances.ContainsKey(ion) ? 0 : _abundances[ion];

                _abundances[ion] = current + abundance;
            }
예제 #6
0
        private TransitionDocNode GetMatchingTransition(SrmSettings settings,
                                                        TransitionGroupDocNode nodeGroupMatching,
                                                        TransitionDocNode nodeTran,
                                                        IFragmentMassCalc calc)
        {
            var transition     = nodeTran.Transition;
            var losses         = nodeTran.Losses;
            var libInfo        = nodeTran.LibInfo;
            int?decoyMassShift = transition.IsPrecursor() ? DecoyMassShift : transition.DecoyMassShift;
            var tranNew        = new Transition(this,
                                                transition.IonType,
                                                transition.CleavageOffset,
                                                transition.MassIndex,
                                                transition.Adduct,
                                                decoyMassShift,
                                                transition.CustomIon ?? CustomMolecule); // Handle reporter ions as well as small molecules
            var       isotopeDist = nodeGroupMatching.IsotopeDist;
            TypedMass massH;
            var       massType = calc.MassType;

            if (tranNew.IsCustom())
            {
                massH = tranNew.CustomIon.GetMass(massType);
            }
            else
            {
                massH = calc.GetFragmentMass(tranNew, isotopeDist);
            }
            var isotopeDistInfo  = TransitionDocNode.GetIsotopeDistInfo(tranNew, losses, isotopeDist);
            var nodeTranMatching = new TransitionDocNode(tranNew, losses, massH, new TransitionDocNode.TransitionQuantInfo(isotopeDistInfo, libInfo, nodeTran.IsQuantitative(settings)), nodeTran.ExplicitValues);

            return(nodeTranMatching);
        }
예제 #7
0
        private TransitionDocNode CreateTransitionNode(IonType type, int cleavageOffset, int charge, double massH,
                                                       TransitionLosses losses, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, CustomIon customIon = null)
        {
            Transition transition = new Transition(this, type, cleavageOffset, 0, charge, null, customIon);
            var        info       = TransitionDocNode.GetLibInfo(transition, Transition.CalcMass(massH, losses), transitionRanks);

            return(new TransitionDocNode(transition, losses, massH, null, info));
        }
예제 #8
0
        private TransitionDocNode CreateTransitionNode(int massIndex, double precursorMassH, TransitionIsotopeDistInfo isotopeDistInfo,
                                                       TransitionLosses losses, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, CustomIon customIon = null)
        {
            Transition transition = new Transition(this, massIndex, customIon);
            var        info       = isotopeDistInfo == null?TransitionDocNode.GetLibInfo(transition, Transition.CalcMass(precursorMassH, losses), transitionRanks) : null;

            return(new TransitionDocNode(transition, losses, precursorMassH, isotopeDistInfo, info));
        }
예제 #9
0
        public static int CompareTransitions(TransitionDocNode node1, TransitionDocNode node2)
        {
            int result = CompareTransitionIds(node1.Transition, node2.Transition);

            if (result == 0)
            {
                result = node1.LostMass.CompareTo(node2.LostMass);
            }
            return(result);
        }
예제 #10
0
        public static double FindOptimizedValue(SrmSettings settings,
                                                PeptideDocNode nodePep,
                                                TransitionGroupDocNode nodeGroup,
                                                TransitionDocNode nodeTran,
                                                OptimizedMethodType methodType,
                                                TReg regressionDocument,
                                                GetRegressionValue getRegressionValue)
        {
            double?optimizedValue = FindOptimizedValueFromResults(settings, nodePep, nodeGroup, nodeTran, methodType, getRegressionValue);

            return(optimizedValue.HasValue ? optimizedValue.Value : getRegressionValue(settings, nodePep, nodeGroup, regressionDocument, 0));
        }
예제 #11
0
        private TransitionDocNode CreateTransitionNode(int massIndex, TypedMass precursorMassH, TransitionIsotopeDistInfo isotopeDistInfo,
                                                       TransitionLosses losses, IDictionary <double, LibraryRankedSpectrumInfo.RankedMI> transitionRanks, CustomMolecule customMolecule = null)
        {
            Transition transition = new Transition(this, massIndex, customMolecule);
            var        quantInfo  = TransitionDocNode.TransitionQuantInfo.GetLibTransitionQuantInfo(transition, losses,
                                                                                                    Transition.CalcMass(precursorMassH, losses), transitionRanks).ChangeIsotopeDistInfo(isotopeDistInfo);
            var transitionDocNode = new TransitionDocNode(transition, losses, precursorMassH, quantInfo);

            if (massIndex < 0)
            {
                transitionDocNode = transitionDocNode.ChangeQuantitative(false);
            }
            return(transitionDocNode);
        }
예제 #12
0
        public TransitionDocNode MergeUserInfo(SrmSettings settings, TransitionDocNode nodeTranMerge)
        {
            var result      = this;
            var annotations = Annotations.Merge(nodeTranMerge.Annotations);

            if (!ReferenceEquals(annotations, Annotations))
            {
                result = (TransitionDocNode)result.ChangeAnnotations(annotations);
            }
            var resultsInfo = MergeResultsUserInfo(settings, nodeTranMerge.Results);

            if (!ReferenceEquals(resultsInfo, Results))
            {
                result = result.ChangeResults(resultsInfo);
            }
            return(result);
        }
예제 #13
0
        public bool Equals(TransitionDocNode obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return(false);
            }
            if (ReferenceEquals(this, obj))
            {
                return(true);
            }
            var equal = base.Equals(obj) && obj.Mz == Mz &&
                        Equals(obj.IsotopeDistInfo, IsotopeDistInfo) &&
                        Equals(obj.LibInfo, LibInfo) &&
                        Equals(obj.Results, Results);

            return(equal);  // For debugging convenience
        }
예제 #14
0
        public static int CompareTransitions(TransitionDocNode node1, TransitionDocNode node2)
        {
            Transition tran1 = node1.Transition, tran2 = node2.Transition;
            int        diffType = GetOrder(tran1.IonType) - GetOrder(tran2.IonType);

            if (diffType != 0)
            {
                return(diffType);
            }
            int diffCharge = tran1.Charge - tran2.Charge;

            if (diffCharge != 0)
            {
                return(diffCharge);
            }
            int diffOffset = tran1.CleavageOffset - tran2.CleavageOffset;

            if (diffOffset != 0)
            {
                return(diffOffset);
            }
            return(Comparer <double> .Default.Compare(node1.LostMass, node2.LostMass));
        }
예제 #15
0
        public static FragmentedMolecule GetFragmentedMolecule(SrmSettings settings, PeptideDocNode peptideDocNode,
                                                               TransitionGroupDocNode transitionGroupDocNode, TransitionDocNode transitionDocNode)
        {
            FragmentedMolecule fragmentedMolecule = EMPTY
                                                    .ChangePrecursorMassShift(0, settings.TransitionSettings.Prediction.PrecursorMassType)
                                                    .ChangeFragmentMassShift(0, settings.TransitionSettings.Prediction.FragmentMassType);

            if (peptideDocNode == null)
            {
                return(fragmentedMolecule);
            }
            var labelType = transitionGroupDocNode == null
                ? IsotopeLabelType.light
                : transitionGroupDocNode.TransitionGroup.LabelType;

            if (peptideDocNode.IsProteomic)
            {
                fragmentedMolecule = fragmentedMolecule.ChangeModifiedSequence(
                    ModifiedSequence.GetModifiedSequence(settings, peptideDocNode, labelType));
                if (transitionGroupDocNode != null)
                {
                    fragmentedMolecule = fragmentedMolecule
                                         .ChangePrecursorCharge(transitionGroupDocNode.PrecursorCharge);
                }
                if (transitionDocNode == null || transitionDocNode.IsMs1)
                {
                    return(fragmentedMolecule);
                }
                var transition = transitionDocNode.Transition;
                fragmentedMolecule = fragmentedMolecule
                                     .ChangeFragmentIon(transition.IonType, transition.Ordinal)
                                     .ChangeFragmentCharge(transition.Charge);
                var transitionLosses = transitionDocNode.Losses;
                if (transitionLosses != null)
                {
                    var fragmentLosses = transitionLosses.Losses.Select(transitionLoss => transitionLoss.Loss);
                    fragmentedMolecule = fragmentedMolecule.ChangeFragmentLosses(fragmentLosses);
                }
                return(fragmentedMolecule);
            }
            if (transitionGroupDocNode == null)
            {
                return(fragmentedMolecule
                       .ChangePrecursorFormula(
                           Molecule.Parse(peptideDocNode.CustomMolecule.Formula ?? string.Empty)));
            }
            var customMolecule = transitionGroupDocNode.CustomMolecule;

            fragmentedMolecule =
                fragmentedMolecule.ChangePrecursorCharge(transitionGroupDocNode.TransitionGroup
                                                         .PrecursorCharge);
            if (customMolecule.Formula != null)
            {
                var ionInfo = new IonInfo(customMolecule.Formula,
                                          transitionGroupDocNode.PrecursorAdduct);
                fragmentedMolecule = fragmentedMolecule
                                     .ChangePrecursorFormula(Molecule.Parse(ionInfo.FormulaWithAdductApplied));
            }
            else
            {
                fragmentedMolecule = fragmentedMolecule.ChangePrecursorMassShift(
                    transitionGroupDocNode.PrecursorAdduct.MassFromMz(
                        transitionGroupDocNode.PrecursorMz, transitionGroupDocNode.PrecursorMzMassType),
                    transitionGroupDocNode.PrecursorMzMassType);
            }
            if (transitionDocNode == null || transitionDocNode.IsMs1)
            {
                return(fragmentedMolecule);
            }
            var customIon = transitionDocNode.Transition.CustomIon;

            if (customIon.Formula != null)
            {
                fragmentedMolecule = fragmentedMolecule.ChangeFragmentFormula(
                    Molecule.Parse(customIon.FormulaWithAdductApplied));
            }
            else
            {
                fragmentedMolecule = fragmentedMolecule.ChangeFragmentMassShift(
                    transitionDocNode.Transition.Adduct.MassFromMz(
                        transitionDocNode.Mz, transitionDocNode.MzMassType),
                    transitionDocNode.MzMassType);
            }
            fragmentedMolecule = fragmentedMolecule
                                 .ChangeFragmentCharge(transitionDocNode.Transition.Charge);
            return(fragmentedMolecule);
        }
예제 #16
0
        public Chromatogram[] GetChromatograms(DocumentLocation documentLocation)
        {
            if (documentLocation == null)
            {
                return(new Chromatogram[0]);
            }
            var               result            = new List <Chromatogram>();
            SrmDocument       document          = Program.MainWindow.Document;
            Bookmark          bookmark          = Bookmark.ToBookmark(documentLocation, document);
            IdentityPath      identityPath      = bookmark.IdentityPath;
            var               nodeList          = GetDocNodes(identityPath, document);
            TransitionDocNode transitionDocNode = null;

            if (nodeList.Count > 3)
            {
                transitionDocNode = (TransitionDocNode)nodeList[3];
            }
            var measuredResults = document.Settings.MeasuredResults;
            var nodePep         = (PeptideDocNode)(nodeList.Count > 1 ? nodeList[1] : null);

            if (null == nodePep)
            {
                return(result.ToArray());
            }

            int iColor = 0;

            foreach (var chromatogramSet in measuredResults.Chromatograms)
            {
                foreach (var msDataFileInfo in chromatogramSet.MSDataFileInfos)
                {
                    if (bookmark.ChromFileInfoId != null && !ReferenceEquals(msDataFileInfo.FileId, bookmark.ChromFileInfoId))
                    {
                        continue;
                    }

                    foreach (var nodeGroup in nodePep.TransitionGroups)
                    {
                        if (nodeList.Count > 2 && !Equals(nodeGroup, nodeList[2]))
                        {
                            continue;
                        }
                        ChromatogramGroupInfo[] arrayChromInfo;
                        measuredResults.TryLoadChromatogram(
                            chromatogramSet,
                            nodePep,
                            nodeGroup,
                            (float)document.Settings.TransitionSettings.Instrument.MzMatchTolerance,
                            true,
                            out arrayChromInfo);
                        foreach (var transition in nodeGroup.Transitions)
                        {
                            if (transitionDocNode != null && !Equals(transitionDocNode, transition))
                            {
                                continue;
                            }
                            foreach (var chromatogramGroup in arrayChromInfo)
                            {
                                for (int iTransition = 0; iTransition < chromatogramGroup.NumTransitions; iTransition++)
                                {
                                    ChromatogramInfo transitionInfo = chromatogramGroup.GetTransitionInfo(iTransition);
                                    if (Math.Abs(transitionInfo.ProductMz - transition.Mz) >
                                        document.Settings.TransitionSettings.Instrument.MzMatchTolerance)
                                    {
                                        continue;
                                    }
                                    Color color = GraphChromatogram.COLORS_LIBRARY[iColor % GraphChromatogram.COLORS_LIBRARY.Count];
                                    iColor++;
                                    result.Add(new Chromatogram
                                    {
                                        Intensities = transitionInfo.Intensities.ToArray(),
                                        ProductMz   = transitionInfo.ProductMz.RawValue,      // For negative ion mode data this will be a negative value
                                        PrecursorMz = chromatogramGroup.PrecursorMz.RawValue, // For negative ion mode data this will be a negative value
                                        Times       = transitionInfo.Times.ToArray(),
                                        Color       = color
                                    });
                                }
                            }
                        }
                    }
                }
            }

            if (result.Count == 1)
            {
                result[0].Color = ChromGraphItem.ColorSelected;
            }


            return(result.ToArray());
        }
예제 #17
0
 /// <summary>
 /// In the case of small molecule transitions specified by mass only, position within
 /// the parent's list of transitions is the only meaningful key.  So we need to know our parent.
 /// </summary>
 public TransitionLossEquivalentKey(TransitionGroupDocNode parent, TransitionDocNode transition, TransitionLosses losses)
 {
     Key    = new TransitionEquivalentKey(parent, transition);
     Losses = losses;
 }
 protected virtual bool SkipTransition(PeptideGroupDocNode nodePepGroup, PeptideDocNode nodePep,
                                       TransitionGroupDocNode nodeGroup, TransitionGroupDocNode nodeGroupPrimary, TransitionDocNode nodeTran)
 {
     return(false);
 }
예제 #19
0
        private readonly string _customIonEquivalenceTestText; // For use with small molecules

        public TransitionEquivalentKey(TransitionGroupDocNode parent, TransitionDocNode nodeTran)
        {
            _nodeTran = nodeTran.Transition;
            _customIonEquivalenceTestText = new TransitionLossKey(parent, nodeTran, null).CustomIonEquivalenceTestValue;
        }
예제 #20
0
        public static double?FindOptimizedValueFromResults(SrmSettings settings,
                                                           PeptideDocNode nodePep,
                                                           TransitionGroupDocNode nodeGroup,
                                                           TransitionDocNode nodeTran,
                                                           OptimizedMethodType methodType,
                                                           GetRegressionValue getRegressionValue)
        {
            // Collect peak area for
            var dictOptTotals = new Dictionary <TReg, Dictionary <int, OptimizationStep <TReg> > >();

            if (settings.HasResults)
            {
                var chromatograms = settings.MeasuredResults.Chromatograms;
                for (int i = 0; i < chromatograms.Count; i++)
                {
                    var chromSet   = chromatograms[i];
                    var regression = chromSet.OptimizationFunction as TReg;
                    if (regression == null)
                    {
                        continue;
                    }

                    Dictionary <int, OptimizationStep <TReg> > stepAreas;
                    if (!dictOptTotals.TryGetValue(regression, out stepAreas))
                    {
                        dictOptTotals.Add(regression, stepAreas = new Dictionary <int, OptimizationStep <TReg> >());
                    }

                    if (methodType == OptimizedMethodType.Precursor)
                    {
                        TransitionGroupDocNode[] listGroups = FindCandidateGroups(nodePep, nodeGroup);
                        foreach (var nodeGroupCandidate in listGroups)
                        {
                            AddOptimizationStepAreas(nodeGroupCandidate, i, regression, stepAreas);
                        }
                    }
                    else if (methodType == OptimizedMethodType.Transition)
                    {
                        IEnumerable <TransitionDocNode> listTransitions = FindCandidateTransitions(nodePep, nodeGroup, nodeTran);
                        foreach (var nodeTranCandidate in listTransitions)
                        {
                            AddOptimizationStepAreas(nodeTranCandidate, i, regression, stepAreas);
                        }
                    }
                }
            }
            // If no candidate values were found, use the document regressor.
            if (dictOptTotals.Count == 0)
            {
                return(null);
            }

            // Get the CE value with the maximum total peak area
            double maxArea   = 0;
            double bestValue = 0;

            foreach (var optTotals in dictOptTotals.Values)
            {
                foreach (var optStep in optTotals.Values)
                {
                    if (maxArea < optStep.TotalArea)
                    {
                        maxArea   = optStep.TotalArea;
                        bestValue = getRegressionValue(settings, nodePep, nodeGroup, optStep.Regression, optStep.Step);
                    }
                }
            }
            // Use value for candidate with the largest area
            return(bestValue);
        }
예제 #21
0
        private static IEnumerable <TransitionDocNode> FindCandidateTransitions(PeptideDocNode nodePep, TransitionGroupDocNode nodeGroup, TransitionDocNode nodeTran)
        {
            var candidateGroups = FindCandidateGroups(nodePep, nodeGroup);

            if (candidateGroups.Length < 2)
            {
                return new[] { nodeTran }
            }
            ;
            Debug.Assert(ReferenceEquals(nodeGroup, candidateGroups[0]));
            var listCandidates = new List <TransitionDocNode> {
                nodeTran
            };
            var transition = nodeTran.Transition;

            for (int i = 1; i < candidateGroups.Length; i++)
            {
                foreach (TransitionDocNode nodeTranCandidate in candidateGroups[i].Children)
                {
                    var transitionCandidate = nodeTranCandidate.Transition;
                    if (transition.Charge == transitionCandidate.Charge &&
                        transition.Ordinal == transitionCandidate.Ordinal &&
                        transition.IonType == transitionCandidate.IonType)
                    {
                        listCandidates.Add(nodeTranCandidate);
                        break;
                    }
                }
            }
            return(listCandidates.ToArray());
        }
예제 #22
0
 public static ExplicitTransitionValues Get(TransitionDocNode node)
 {
     return(node == null ? EMPTY : node.ExplicitValues);
 }                                                                                                                        // Convenience function
예제 #23
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);
                            }
                        }
                    }
                }
            }
        }