Exemple #1
0
        private void PopulateChoices()
        {
            TheList = new ObservableCollection <BoolStringClass>();

            var knownProductTypes = Enum.GetValues(typeof(ProductType)).Cast <ProductType>().ToList();

            knownProductTypes.Remove(ProductType.D);
            knownProductTypes.Remove(ProductType.M);
            knownProductTypes.Remove(ProductType.Y);
            knownProductTypes.Remove(ProductType.Ycore);
            knownProductTypes.Remove(ProductType.zPlusOne);
            knownProductTypes.Remove(ProductType.Ycore);
            knownProductTypes.Remove(ProductType.Y);

            foreach (ProductType productType in knownProductTypes)
            {
                TheList.Add(new BoolStringClass {
                    IsSelected = false,
                    Type       = productType,
                    ToolTip    = DissociationTypeCollection.GetMassShiftFromProductType(productType).ToString("F4") + " Da; "
                                 + TerminusSpecificProductTypes.ProductTypeToFragmentationTerminus[productType] + " terminus"
                });
            }

            ProductTypeList.ItemsSource = TheList;
        }
        private static List <MatchedFragmentIon> ReadFragmentIonsFromString(string matchedMzString, string peptideBaseSequence)
        {
            var peaks = matchedMzString.Split(MzSplit, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim())
                        .ToList();

            peaks.RemoveAll(p => p.Contains("\""));

            List <MatchedFragmentIon> matchedIons = new List <MatchedFragmentIon>();

            foreach (var peak in peaks)
            {
                var split = peak.Split(new char[] { '+', ':' });

                string ionTypeAndNumber = split[0];
                Match  result           = IonParser.Match(ionTypeAndNumber);

                ProductType productType = (ProductType)Enum.Parse(typeof(ProductType), result.Groups[1].Value);

                int    fragmentNumber = int.Parse(result.Groups[2].Value);
                int    z           = int.Parse(split[1]);
                double mz          = double.Parse(split[2], CultureInfo.InvariantCulture);
                double neutralLoss = 0;

                // check for neutral loss
                if (ionTypeAndNumber.Contains("-"))
                {
                    string temp = ionTypeAndNumber.Replace("(", "");
                    temp = temp.Replace(")", "");
                    var split2 = temp.Split('-');
                    neutralLoss = double.Parse(split2[1], CultureInfo.InvariantCulture);
                }

                FragmentationTerminus terminus = FragmentationTerminus.None;
                if (TerminusSpecificProductTypes.ProductTypeToFragmentationTerminus.ContainsKey(productType))
                {
                    terminus = TerminusSpecificProductTypes.ProductTypeToFragmentationTerminus[productType];
                }

                int aminoAcidPosition = fragmentNumber;
                if (terminus == FragmentationTerminus.C)
                {
                    aminoAcidPosition = peptideBaseSequence.Length - fragmentNumber;
                }

                Product p = new Product(productType,
                                        terminus,
                                        mz.ToMass(z) - DissociationTypeCollection.GetMassShiftFromProductType(productType),
                                        fragmentNumber,
                                        aminoAcidPosition,
                                        neutralLoss);

                matchedIons.Add(new MatchedFragmentIon(ref p, mz, 1.0, z));
            }

            return(matchedIons);
        }
Exemple #3
0
        protected override MetaMorpheusEngineResults RunSpecific()
        {
            bool semiSpecificSearch = CommonParameters.DigestionParams.SearchModeType == CleavageSpecificity.Semi;

            double progress           = 0;
            int    oldPercentProgress = 0;

            ReportProgress(new ProgressEventArgs(oldPercentProgress, "Performing nonspecific search... " + CurrentPartition + "/" + CommonParameters.TotalPartitions, NestedIds));

            byte byteScoreCutoff = (byte)CommonParameters.ScoreCutoff;

            int maxThreadsPerFile = CommonParameters.MaxThreadsToUsePerFile;

            int[] threads = Enumerable.Range(0, maxThreadsPerFile).ToArray();
            Parallel.ForEach(threads, (i) =>
            {
                byte[] scoringTable = new byte[PeptideIndex.Count];
                HashSet <int> idsOfPeptidesPossiblyObserved = new HashSet <int>();

                for (; i < ListOfSortedMs2Scans.Length; i += maxThreadsPerFile)
                {
                    // Stop loop if canceled
                    if (GlobalVariables.StopLoops)
                    {
                        return;
                    }

                    // empty the scoring table to score the new scan (conserves memory compared to allocating a new array)
                    Array.Clear(scoringTable, 0, scoringTable.Length);
                    idsOfPeptidesPossiblyObserved.Clear();
                    Ms2ScanWithSpecificMass scan = ListOfSortedMs2Scans[i];

                    //get bins to add points to
                    List <int> allBinsToSearch = GetBinsToSearch(scan, FragmentIndex, CommonParameters.DissociationType);

                    //the entire indexed scoring is done here
                    for (int j = 0; j < allBinsToSearch.Count; j++)
                    {
                        FragmentIndex[allBinsToSearch[j]].ForEach(id => scoringTable[id]++);
                    }

                    //populate ids of possibly observed with those containing allowed precursor masses
                    List <AllowedIntervalWithNotch> validIntervals = MassDiffAcceptor.GetAllowedPrecursorMassIntervalsFromObservedMass(scan.PrecursorMass).ToList(); //get all valid notches
                    foreach (AllowedIntervalWithNotch interval in validIntervals)
                    {
                        int obsPrecursorFloorMz   = (int)Math.Floor(interval.AllowedInterval.Minimum * FragmentBinsPerDalton);
                        int obsPrecursorCeilingMz = (int)Math.Ceiling(interval.AllowedInterval.Maximum * FragmentBinsPerDalton);

                        foreach (ProductType pt in ProductTypesToSearch)
                        {
                            int dissociationBinShift = (int)Math.Round((WaterMonoisotopicMass - DissociationTypeCollection.GetMassShiftFromProductType(pt)) * FragmentBinsPerDalton);
                            int lowestBin            = obsPrecursorFloorMz - dissociationBinShift;
                            int highestBin           = obsPrecursorCeilingMz - dissociationBinShift;
                            for (int bin = lowestBin; bin <= highestBin; bin++)
                            {
                                if (bin < FragmentIndex.Length && FragmentIndex[bin] != null)
                                {
                                    FragmentIndex[bin].ForEach(id => idsOfPeptidesPossiblyObserved.Add(id));
                                }
                            }
                        }

                        for (int bin = obsPrecursorFloorMz; bin <= obsPrecursorCeilingMz; bin++) //no bin shift, since they're precursor masses
                        {
                            if (bin < PrecursorIndex.Length && PrecursorIndex[bin] != null)
                            {
                                PrecursorIndex[bin].ForEach(id => idsOfPeptidesPossiblyObserved.Add(id));
                            }
                        }
                    }

                    // done with initial scoring; refine scores and create PSMs
                    if (idsOfPeptidesPossiblyObserved.Any())
                    {
                        int maxInitialScore = idsOfPeptidesPossiblyObserved.Max(id => scoringTable[id]) + 1;
                        while (maxInitialScore > CommonParameters.ScoreCutoff) //go through all until we hit the end
                        {
                            maxInitialScore--;
                            foreach (int id in idsOfPeptidesPossiblyObserved.Where(id => scoringTable[id] == maxInitialScore))
                            {
                                PeptideWithSetModifications peptide = PeptideIndex[id];
                                List <Product> peptideTheorProducts = peptide.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus).ToList();

                                Tuple <int, PeptideWithSetModifications> notchAndUpdatedPeptide = Accepts(peptideTheorProducts, scan.PrecursorMass, peptide, CommonParameters.DigestionParams.FragmentationTerminus, MassDiffAcceptor, semiSpecificSearch);
                                int notch = notchAndUpdatedPeptide.Item1;
                                if (notch >= 0)
                                {
                                    peptide = notchAndUpdatedPeptide.Item2;
                                    peptideTheorProducts = peptide.Fragment(CommonParameters.DissociationType, FragmentationTerminus.Both).ToList();
                                    List <MatchedFragmentIon> matchedIons = MatchFragmentIons(scan, peptideTheorProducts, ModifiedParametersNoComp);

                                    double thisScore = CalculatePeptideScore(scan.TheScan, matchedIons);
                                    if (thisScore > CommonParameters.ScoreCutoff)
                                    {
                                        PeptideSpectralMatch[] localPeptideSpectralMatches = GlobalCategorySpecificPsms[(int)FdrClassifier.GetCleavageSpecificityCategory(peptide.CleavageSpecificityForFdrCategory)];
                                        if (localPeptideSpectralMatches[i] == null)
                                        {
                                            localPeptideSpectralMatches[i] = new PeptideSpectralMatch(peptide, notch, thisScore, i, scan, CommonParameters.DigestionParams, matchedIons);
                                        }
                                        else
                                        {
                                            localPeptideSpectralMatches[i].AddOrReplace(peptide, thisScore, notch, CommonParameters.ReportAllAmbiguity, matchedIons, 0);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // report search progress
                    progress++;
                    int percentProgress = (int)((progress / ListOfSortedMs2Scans.Length) * 100);

                    if (percentProgress > oldPercentProgress)
                    {
                        oldPercentProgress = percentProgress;
                        ReportProgress(new ProgressEventArgs(percentProgress, "Performing nonspecific search... " + CurrentPartition + "/" + CommonParameters.TotalPartitions, NestedIds));
                    }
                }
            });
            return(new MetaMorpheusEngineResults(this));
        }
Exemple #4
0
        private Tuple <int, PeptideWithSetModifications> Accepts(List <Product> fragments, double scanPrecursorMass, PeptideWithSetModifications peptide, FragmentationTerminus fragmentationTerminus, MassDiffAcceptor searchMode, bool semiSpecificSearch)
        {
            int localminPeptideLength = CommonParameters.DigestionParams.MinPeptideLength;

            //Get terminal modifications, if any
            Dictionary <int, List <Modification> > databaseAnnotatedMods = semiSpecificSearch ? null : GetTerminalModPositions(peptide, CommonParameters.DigestionParams, VariableTerminalModifications);

            for (int i = localminPeptideLength - 1; i < fragments.Count; i++) //minus one start, because fragment 1 is at index 0
            {
                Product fragment = fragments[i];
                double  theoMass = fragment.NeutralMass - DissociationTypeCollection.GetMassShiftFromProductType(fragment.ProductType) + WaterMonoisotopicMass;
                int     notch    = searchMode.Accepts(scanPrecursorMass, theoMass);

                //check for terminal mods that might reach the observed mass
                Modification terminalMod = null;
                if (!semiSpecificSearch && notch < 0 && databaseAnnotatedMods.TryGetValue(i + 1, out List <Modification> terminalModsAtThisIndex)) //look for i+1, because the mod might exist at the terminus
                {
                    foreach (Modification mod in terminalModsAtThisIndex)
                    {
                        notch = searchMode.Accepts(scanPrecursorMass, theoMass + mod.MonoisotopicMass.Value); //overwrite the notch, since the other notch wasn't accepted
                        if (notch >= 0)
                        {
                            terminalMod = mod;
                            break;
                        }
                    }
                }

                if (notch >= 0)
                {
                    PeptideWithSetModifications updatedPwsm = null;
                    if (fragmentationTerminus == FragmentationTerminus.N)
                    {
                        int endResidue = peptide.OneBasedStartResidueInProtein + fragment.TerminusFragment.FragmentNumber - 1; //-1 for one based index
                        Dictionary <int, Modification> updatedMods = new Dictionary <int, Modification>();
                        foreach (KeyValuePair <int, Modification> mod in peptide.AllModsOneIsNterminus)
                        {
                            if (mod.Key < endResidue - peptide.OneBasedStartResidueInProtein + 3) //check if we cleaved it off, +1 for N-terminus being mod 1 and first residue being mod 2, +1 again for the -1 on end residue for one based index, +1 (again) for the one-based start residue
                            {
                                updatedMods.Add(mod.Key, mod.Value);
                            }
                        }
                        if (terminalMod != null)
                        {
                            updatedMods.Add(endResidue, terminalMod);
                        }
                        updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, peptide.OneBasedStartResidueInProtein, endResidue, CleavageSpecificity.Unknown, "", 0, updatedMods, 0);
                    }
                    else //if C terminal ions, shave off the n-terminus
                    {
                        int startResidue = peptide.OneBasedEndResidueInProtein - fragment.TerminusFragment.FragmentNumber + 1; //plus one for one based index
                        Dictionary <int, Modification> updatedMods = new Dictionary <int, Modification>();  //updateMods
                        int indexShift = startResidue - peptide.OneBasedStartResidueInProtein;
                        foreach (KeyValuePair <int, Modification> mod in peptide.AllModsOneIsNterminus)
                        {
                            if (mod.Key > indexShift + 1) //check if we cleaved it off, +1 for N-terminus being mod 1 and first residue being 2
                            {
                                int key = mod.Key - indexShift;
                                updatedMods.Add(key, mod.Value);
                            }
                        }
                        if (terminalMod != null)
                        {
                            updatedMods.Add(startResidue - 1, terminalMod);
                        }
                        updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, startResidue, peptide.OneBasedEndResidueInProtein, CleavageSpecificity.Unknown, "", 0, updatedMods, 0);
                    }
                    return(new Tuple <int, PeptideWithSetModifications>(notch, updatedPwsm));
                }
                else if (theoMass > scanPrecursorMass)
                {
                    break;
                }
            }

            //if the theoretical and experimental have the same mass or a terminal mod exists
            if (peptide.BaseSequence.Length >= localminPeptideLength)
            {
                double totalMass = peptide.MonoisotopicMass;// + Constants.ProtonMass;
                int    notch     = searchMode.Accepts(scanPrecursorMass, totalMass);
                if (notch >= 0)
                {
                    //need to update so that the cleavage specificity is recorded
                    PeptideWithSetModifications updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, peptide.OneBasedStartResidueInProtein, peptide.OneBasedEndResidueInProtein, CleavageSpecificity.Unknown, "", 0, peptide.AllModsOneIsNterminus, peptide.NumFixedMods);
                    return(new Tuple <int, PeptideWithSetModifications>(notch, updatedPwsm));
                }
                else //try a terminal mod (if it exists)
                {
                    if (!semiSpecificSearch && databaseAnnotatedMods.TryGetValue(peptide.Length, out List <Modification> terminalModsAtThisIndex))
                    {
                        foreach (Modification terminalMod in terminalModsAtThisIndex)
                        {
                            notch = searchMode.Accepts(scanPrecursorMass, totalMass + terminalMod.MonoisotopicMass.Value); //overwrite the notch, since the other notch wasn't accepted
                            if (notch >= 0)
                            {
                                //need to update the mod dictionary and don't want to overwrite the peptide incase it's in other scans
                                Dictionary <int, Modification> updatedMods = new Dictionary <int, Modification>();  //updateMods
                                foreach (KeyValuePair <int, Modification> mod in peptide.AllModsOneIsNterminus)
                                {
                                    updatedMods.Add(mod.Key, mod.Value);
                                }

                                //add the terminal mod
                                if (fragmentationTerminus == FragmentationTerminus.N)
                                {
                                    updatedMods[peptide.OneBasedEndResidueInProtein] = terminalMod;
                                }
                                else
                                {
                                    updatedMods[peptide.OneBasedStartResidueInProtein - 1] = terminalMod;
                                }

                                PeptideWithSetModifications updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, peptide.OneBasedStartResidueInProtein, peptide.OneBasedEndResidueInProtein, CleavageSpecificity.Unknown, "", 0, updatedMods, peptide.NumFixedMods);
                                return(new Tuple <int, PeptideWithSetModifications>(notch, updatedPwsm));
                            }
                        }
                    }
                }
            }
            return(new Tuple <int, PeptideWithSetModifications>(-1, null));
        }
        /// <summary>
        /// Generates theoretical fragments for given dissociation type for this peptide.
        /// The "products" parameter is filled with these fragments.
        /// </summary>
        public void Fragment(DissociationType dissociationType, FragmentationTerminus fragmentationTerminus, List <Product> products)
        {
            // This code is specifically written to be memory- and CPU -efficient because it is
            // called millions of times for a typical search (i.e., at least once per peptide).
            // If you modify this code, BE VERY CAREFUL about allocating new memory, especially
            // for new collections. This code also deliberately avoids using "yield return", again
            // for performance reasons. Be sure to benchmark any changes with a parallelized
            // fragmentation of every peptide in a database (i.e., test for speed decreases and
            // memory issues).

            products.Clear();

            var massCaps = DissociationTypeCollection.GetNAndCTerminalMassShiftsForDissociationType(dissociationType);

            double cTermMass = 0;
            double nTermMass = 0;

            List <ProductType> nTermProductTypes = DissociationTypeCollection.GetTerminusSpecificProductTypesFromDissociation(dissociationType, FragmentationTerminus.N);
            List <ProductType> cTermProductTypes = DissociationTypeCollection.GetTerminusSpecificProductTypesFromDissociation(dissociationType, FragmentationTerminus.C);

            bool calculateNTermFragments = fragmentationTerminus == FragmentationTerminus.N ||
                                           fragmentationTerminus == FragmentationTerminus.Both;

            bool calculateCTermFragments = fragmentationTerminus == FragmentationTerminus.C ||
                                           fragmentationTerminus == FragmentationTerminus.Both;

            //From http://www.matrixscience.com/help/fragmentation_help.html
            //Low Energy CID -- In low energy CID(i.e.collision induced dissociation in a triple quadrupole or an ion trap) a peptide carrying a positive charge fragments mainly along its backbone,
            //generating predominantly b and y ions. In addition, for fragments containing RKNQ, peaks are seen for ions that have lost ammonia (-17 Da) denoted a*, b* and y*. For fragments containing
            //STED, loss of water(-18 Da) is denoted a°, b° and y°. Satellite ions from side chain cleavage are not observed.
            bool haveSeenNTermDegreeIon = false;
            bool haveSeenNTermStarIon   = false;
            bool haveSeenCTermDegreeIon = false;
            bool haveSeenCTermStarIon   = false;

            // these two collections keep track of the neutral losses observed so far on the n-term or c-term.
            // they are apparently necessary, but allocating memory for collections in this function results in
            // inefficient memory usage and thus frequent garbage collection.
            // TODO: If you can think of a way to remove these collections and still maintain correct
            // fragmentation, please do so.
            HashSet <double> nTermNeutralLosses = null;
            HashSet <double> cTermNeutralLosses = null;

            // n-terminus mod
            if (calculateNTermFragments)
            {
                if (AllModsOneIsNterminus.TryGetValue(1, out Modification mod))
                {
                    nTermMass += mod.MonoisotopicMass.Value;
                }
            }

            // c-terminus mod
            if (calculateCTermFragments)
            {
                if (AllModsOneIsNterminus.TryGetValue(BaseSequence.Length + 2, out Modification mod))
                {
                    cTermMass += mod.MonoisotopicMass.Value;
                }
            }

            for (int r = 0; r < BaseSequence.Length - 1; r++)
            {
                // n-term fragments
                if (calculateNTermFragments)
                {
                    char nTermResidue = BaseSequence[r];

                    // get n-term residue mass
                    if (Residue.TryGetResidue(nTermResidue, out Residue residue))
                    {
                        nTermMass += residue.MonoisotopicMass;
                    }
                    else
                    {
                        nTermMass = double.NaN;
                    }

                    // add side-chain mod
                    if (AllModsOneIsNterminus.TryGetValue(r + 2, out Modification mod))
                    {
                        nTermMass += mod.MonoisotopicMass.Value;
                    }

                    // handle star and degree ions for low-res CID
                    if (dissociationType == DissociationType.LowCID)
                    {
                        if (nTermResidue == 'R' || nTermResidue == 'K' || nTermResidue == 'N' || nTermResidue == 'Q')
                        {
                            haveSeenNTermStarIon = true;
                        }

                        if (nTermResidue == 'S' || nTermResidue == 'T' || nTermResidue == 'E' || nTermResidue == 'D')
                        {
                            haveSeenNTermDegreeIon = true;
                        }
                    }

                    // skip first N-terminal fragment (b1, aDegree1, ...) for CID
                    if (r == 0 && (dissociationType == DissociationType.CID || dissociationType == DissociationType.LowCID))
                    {
                        goto CTerminusFragments;
                    }

                    // generate products
                    for (int i = 0; i < nTermProductTypes.Count; i++)
                    {
                        if (dissociationType == DissociationType.LowCID)
                        {
                            if (!haveSeenNTermStarIon && (nTermProductTypes[i] == ProductType.aStar || nTermProductTypes[i] == ProductType.bStar))
                            {
                                continue;
                            }

                            if (!haveSeenNTermDegreeIon && (nTermProductTypes[i] == ProductType.aDegree || nTermProductTypes[i] == ProductType.bDegree))
                            {
                                continue;
                            }
                        }

                        products.Add(new Product(
                                         nTermProductTypes[i],
                                         FragmentationTerminus.N,
                                         nTermMass + massCaps.Item1[i],
                                         r + 1,
                                         r + 1,
                                         0));

                        if (mod != null && mod.NeutralLosses != null &&
                            mod.NeutralLosses.TryGetValue(dissociationType, out List <double> neutralLosses))
                        {
                            foreach (double neutralLoss in neutralLosses.Where(p => p != 0))
                            {
                                if (nTermNeutralLosses == null)
                                {
                                    nTermNeutralLosses = new HashSet <double>();
                                }

                                nTermNeutralLosses.Add(neutralLoss);
                            }
                        }

                        if (nTermNeutralLosses != null)
                        {
                            foreach (double neutralLoss in nTermNeutralLosses)
                            {
                                products.Add(new Product(
                                                 nTermProductTypes[i],
                                                 FragmentationTerminus.N,
                                                 nTermMass + massCaps.Item1[i] - neutralLoss,
                                                 r + 1,
                                                 r + 1,
                                                 neutralLoss));
                            }
                        }
                    }
                }

                // c-term fragments
CTerminusFragments:
                if (calculateCTermFragments)
                {
                    char cTermResidue = BaseSequence[BaseSequence.Length - r - 1];

                    // get c-term residue mass
                    if (Residue.TryGetResidue(cTermResidue, out Residue residue))
                    {
                        cTermMass += residue.MonoisotopicMass;
                    }
                    else
                    {
                        cTermMass = double.NaN;
                    }

                    // add side-chain mod
                    if (AllModsOneIsNterminus.TryGetValue(BaseSequence.Length - r + 1, out Modification mod))
                    {
                        cTermMass += mod.MonoisotopicMass.Value;
                    }

                    // handle star and degree ions for low-res CID
                    if (dissociationType == DissociationType.LowCID)
                    {
                        if (cTermResidue == 'R' || cTermResidue == 'K' || cTermResidue == 'N' || cTermResidue == 'Q')
                        {
                            haveSeenCTermStarIon = true;
                        }

                        if (cTermResidue == 'S' || cTermResidue == 'T' || cTermResidue == 'E' || cTermResidue == 'D')
                        {
                            haveSeenCTermDegreeIon = true;
                        }
                    }

                    // generate products
                    for (int i = 0; i < cTermProductTypes.Count; i++)
                    {
                        // skip zDot ions for proline residues for ETD/ECD/EThcD
                        if (cTermResidue == 'P' &&
                            (dissociationType == DissociationType.ECD || dissociationType == DissociationType.ETD || dissociationType == DissociationType.EThcD) &&
                            cTermProductTypes[i] == ProductType.zDot)
                        {
                            continue;
                        }

                        if (dissociationType == DissociationType.LowCID)
                        {
                            if (!haveSeenCTermStarIon && cTermProductTypes[i] == ProductType.yStar)
                            {
                                continue;
                            }

                            if (!haveSeenCTermDegreeIon && cTermProductTypes[i] == ProductType.yDegree)
                            {
                                continue;
                            }
                        }

                        products.Add(new Product(
                                         cTermProductTypes[i],
                                         FragmentationTerminus.C,
                                         cTermMass + massCaps.Item2[i],
                                         r + 1,
                                         BaseSequence.Length - r,
                                         0));

                        if (mod != null && mod.NeutralLosses != null &&
                            mod.NeutralLosses.TryGetValue(dissociationType, out List <double> neutralLosses))
                        {
                            foreach (double neutralLoss in neutralLosses.Where(p => p != 0))
                            {
                                if (cTermNeutralLosses == null)
                                {
                                    cTermNeutralLosses = new HashSet <double>();
                                }

                                cTermNeutralLosses.Add(neutralLoss);
                            }
                        }

                        if (cTermNeutralLosses != null)
                        {
                            foreach (double neutralLoss in cTermNeutralLosses)
                            {
                                products.Add(new Product(
                                                 cTermProductTypes[i],
                                                 FragmentationTerminus.C,
                                                 cTermMass + massCaps.Item2[i] - neutralLoss,
                                                 r + 1,
                                                 BaseSequence.Length - r,
                                                 neutralLoss));
                            }
                        }
                    }
                }
            }

            // zDot generates one more ion...
            if (cTermProductTypes.Contains(ProductType.zDot) && BaseSequence[0] != 'P')
            {
                // get c-term residue mass
                if (Residue.TryGetResidue(BaseSequence[0], out Residue residue))
                {
                    cTermMass += residue.MonoisotopicMass;
                }
                else
                {
                    cTermMass = double.NaN;
                }

                // add side-chain mod
                if (AllModsOneIsNterminus.TryGetValue(1, out Modification mod))
                {
                    cTermMass += mod.MonoisotopicMass.Value;
                }

                // generate zDot product
                products.Add(new Product(
                                 ProductType.zDot,
                                 FragmentationTerminus.C,
                                 cTermMass + DissociationTypeCollection.GetMassShiftFromProductType(ProductType.zDot),
                                 BaseSequence.Length,
                                 1,
                                 0));

                if (mod != null && mod.NeutralLosses != null &&
                    mod.NeutralLosses.TryGetValue(dissociationType, out List <double> neutralLosses))
                {
                    foreach (double neutralLoss in neutralLosses.Where(p => p != 0))
                    {
                        products.Add(new Product(
                                         ProductType.zDot,
                                         FragmentationTerminus.C,
                                         cTermMass + DissociationTypeCollection.GetMassShiftFromProductType(ProductType.zDot) - neutralLoss,
                                         BaseSequence.Length,
                                         1,
                                         neutralLoss));
                    }
                }
            }

            foreach (var mod in AllModsOneIsNterminus.Where(p => p.Value.NeutralLosses != null))
            {
                // molecular ion minus neutral losses
                if (mod.Value.NeutralLosses.TryGetValue(dissociationType, out List <double> losses))
                {
                    foreach (double neutralLoss in losses.Where(p => p != 0))
                    {
                        if (neutralLoss != 0)
                        {
                            products.Add(new Product(ProductType.M, FragmentationTerminus.Both, MonoisotopicMass - neutralLoss, 0, 0, neutralLoss));
                        }
                    }
                }
            }

            // generate diagnostic ions
            // TODO: this code is memory-efficient but sort of CPU inefficient; it can be further optimized.
            // however, diagnostic ions are fairly rare so it's probably OK for now
            foreach (double diagnosticIon in AllModsOneIsNterminus.Where(p => p.Value.DiagnosticIons != null &&
                                                                         p.Value.DiagnosticIons.ContainsKey(dissociationType)).SelectMany(p => p.Value.DiagnosticIons[dissociationType]).Distinct())
            {
                int diagnosticIonLabel = (int)Math.Round(diagnosticIon.ToMz(1), 0);

                // the diagnostic ion is assumed to be annotated in the mod info as the *neutral mass* of the diagnostic ion, not the ionized species
                products.Add(new Product(ProductType.D, FragmentationTerminus.Both, diagnosticIon, diagnosticIonLabel, 0, 0));
            }
        }
Exemple #6
0
        private Tuple <int, PeptideWithSetModifications> Accepts(List <Product> fragments, double scanPrecursorMass, PeptideWithSetModifications peptide, FragmentationTerminus fragmentationTerminus, MassDiffAcceptor searchMode)
        {
            //all masses in N and CTerminalMasses are b-ion masses, which are one water away from a full peptide
            int localminPeptideLength = commonParameters.DigestionParams.MinPeptideLength;

            for (int i = localminPeptideLength - 1; i < fragments.Count; i++) //minus one start, because fragment 1 is at index 0
            {
                Product fragment = fragments[i];
                double  theoMass = fragment.NeutralMass - DissociationTypeCollection.GetMassShiftFromProductType(fragment.ProductType) + WaterMonoisotopicMass;
                int     notch    = searchMode.Accepts(scanPrecursorMass, theoMass);
                if (notch >= 0)
                {
                    PeptideWithSetModifications updatedPwsm = null;
                    if (fragmentationTerminus == FragmentationTerminus.N)
                    {
                        int endResidue = peptide.OneBasedStartResidueInProtein + fragment.TerminusFragment.FragmentNumber - 1; //-1 for one based index
                        Dictionary <int, Modification> updatedMods = new Dictionary <int, Modification>();
                        foreach (KeyValuePair <int, Modification> mod in peptide.AllModsOneIsNterminus)
                        {
                            if (mod.Key < endResidue - peptide.OneBasedStartResidueInProtein + 3) //check if we cleaved it off, +1 for N-terminus being mod 1 and first residue being mod 2, +1 again for the -1 on end residue for one based index, +1 (again) for the one-based start residue
                            {
                                updatedMods.Add(mod.Key, mod.Value);
                            }
                        }
                        updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, peptide.OneBasedStartResidueInProtein, endResidue, CleavageSpecificity.Unknown, "", 0, updatedMods, 0);
                    }
                    else
                    {
                        int startResidue = peptide.OneBasedEndResidueInProtein - fragment.TerminusFragment.FragmentNumber + 1; //plus one for one based index
                        Dictionary <int, Modification> updatedMods = new Dictionary <int, Modification>();                     //updateMods
                        int indexShift = startResidue - peptide.OneBasedStartResidueInProtein;
                        foreach (KeyValuePair <int, Modification> mod in peptide.AllModsOneIsNterminus)
                        {
                            if (mod.Key > indexShift + 1) //check if we cleaved it off, +1 for N-terminus being mod 1 and first residue being 2
                            {
                                int key = mod.Key - indexShift;
                                updatedMods.Add(key, mod.Value);
                            }
                        }
                        updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, startResidue, peptide.OneBasedEndResidueInProtein, CleavageSpecificity.Unknown, "", 0, updatedMods, 0);
                    }
                    return(new Tuple <int, PeptideWithSetModifications>(notch, updatedPwsm));
                }
                else if (theoMass > scanPrecursorMass)
                {
                    break;
                }
            }
            //if the theoretical and experimental have the same mass
            if (fragments.Count > localminPeptideLength)
            {
                double totalMass = peptide.MonoisotopicMass;// + Constants.ProtonMass;
                int    notch     = searchMode.Accepts(scanPrecursorMass, totalMass);
                if (notch >= 0)
                {
                    //need to update so that the cleavage specificity is recorded
                    PeptideWithSetModifications updatedPwsm = new PeptideWithSetModifications(peptide.Protein, peptide.DigestionParams, peptide.OneBasedStartResidueInProtein, peptide.OneBasedEndResidueInProtein, CleavageSpecificity.Unknown, "", 0, peptide.AllModsOneIsNterminus, peptide.NumFixedMods);
                    return(new Tuple <int, PeptideWithSetModifications>(notch, updatedPwsm));
                }
            }
            return(new Tuple <int, PeptideWithSetModifications>(-1, null));
        }
        //add possible protein/peptide terminal modifications that aren't on the terminal amino acids
        //The purpose is for terminal mods that are contained WITHIN the Single peptide
        private void AddInteriorTerminalModsToPrecursorIndex(List <int>[] precursorIndex, List <Product> fragmentMasses, PeptideWithSetModifications peptide, int peptideId, List <Modification> variableModifications)
        {
            //Get database annotated mods
            Dictionary <int, List <Modification> > databaseAnnotatedMods = NonSpecificEnzymeSearchEngine.GetTerminalModPositions(peptide, CommonParameters.DigestionParams, variableModifications);

            foreach (KeyValuePair <int, List <Modification> > relevantDatabaseMod in databaseAnnotatedMods)
            {
                int     fragmentNumber    = relevantDatabaseMod.Key;
                Product fragmentAtIndex   = fragmentMasses.Where(x => x.TerminusFragment.FragmentNumber == fragmentNumber).FirstOrDefault();
                double  basePrecursorMass = fragmentAtIndex == null ? peptide.MonoisotopicMass : fragmentAtIndex.NeutralMass - DissociationTypeCollection.GetMassShiftFromProductType(fragmentAtIndex.ProductType) + WaterMonoisotopicMass;

                foreach (Modification mod in relevantDatabaseMod.Value)
                {
                    double modifiedMass = basePrecursorMass + mod.MonoisotopicMass.Value;
                    if (modifiedMass <= MaxFragmentSize) //if the precursor is larger than the index allows, then don't add it
                    {
                        int precursorBin = (int)Math.Round(modifiedMass * FragmentBinsPerDalton);

                        if (precursorIndex[precursorBin] == null)
                        {
                            precursorIndex[precursorBin] = new List <int> {
                                peptideId
                            };
                        }
                        else
                        {
                            precursorIndex[precursorBin].Add(peptideId);
                        }
                    }
                }
            }
        }