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; }
/// <summary> /// A product is the individual neutral fragment from an MS dissociation. A fragmentation product here contains one of the two termini (N- or C-). /// The ProductType describes where along the backbone the fragmentaiton occurred (e.g. b-, y-, c-, zdot-). The neutral loss mass (if any) that /// occurred from a mod on the fragment is listed as a mass. Finally the neutral mass of the whole fragment is provided. /// </summary> public Product(ProductType productType, NeutralTerminusFragment terminusFragment, double neutralLoss) { TerminusFragment = terminusFragment; ProductType = productType; this.NeutralLoss = neutralLoss; NeutralMass = DissociationTypeCollection.ProductTypeSpecificFragmentNeutralMass(terminusFragment.NeutralMass, productType) - neutralLoss; }
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); }
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)); }
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)); } }
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); } } } } }