public override bool TryLoadSpectrum(LibKey key, out SpectrumPeaksInfo spectrum) { spectrum = null; DbSpectrum[] spectra; if (!key.IsPrecursorKey) { spectra = GetSpectraByPeptide(null, key).ToArray(); } else { spectra = GetSpectraByPrecursor(null, key.PrecursorMz.GetValueOrDefault()).ToArray(); var keyRt = key.RetentionTime; if (keyRt.HasValue) { spectra = spectra.Where(s => Equals(keyRt.Value, s.RetentionTime)).ToArray(); } } if (!spectra.Any()) { return(false); } var spec = spectra.First(); var mi = spec.Mzs.Select((t, i) => new SpectrumPeaksInfo.MI { Mz = spec.Mzs[i], Intensity = (float)spec.Intensities[i] }); // CONSIDER(bspratt): annotation? spectrum = new SpectrumPeaksInfo(mi.ToArray()); return(true); }
/// <summary> /// Returns a LibraryRankedSpectrumInfo /// </summary> /// <param name="info">The spectrum to be ranked</param> /// <param name="labelType">The IsotopeLabelType for the peptide in the library. This might be different from the /// LabelType on the GroupDocNode.</param> /// <param name="groupDocNode">The Transition Group from the user's document</param> /// <param name="settings"></param> /// <param name="lookupSequence"></param> /// <param name="lookupMods"></param> /// <param name="charges">The set of charges that the user is choosing to show in the spectrum viewer.</param> /// <param name="types">The set of ion types to be displayed</param> /// <param name="rankCharges">The set of charges that are enabled in the document's Transition Settings</param> /// <param name="rankTypes">The set of ion types in the user's transition settings</param> /// <param name="score">the score to assign to the spectrum. If it is null, then the spectrum gets the score from transition group's LibInfo</param> /// <param name="useFilter">true if this list is being generated in order to show the filtered list of potential transitions</param> /// <param name="matchAll">true if peaks matched peaks should be given a list of all of the ion types that they match, instead /// of only being annotated with the first matching one</param> /// <param name="minPeaks">The minimum number of peaks to match, or -1 to match as many as possible</param> /// <returns></returns> public static LibraryRankedSpectrumInfo RankSpectrum(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroupDocNode groupDocNode, SrmSettings settings, Target lookupSequence, ExplicitMods lookupMods, IEnumerable <Adduct> charges, IEnumerable <IonType> types, IEnumerable <Adduct> rankCharges, IEnumerable <IonType> rankTypes, double?score, bool useFilter, bool matchAll, int minPeaks) { var targetInfo = new TargetInfo(labelType, groupDocNode, lookupSequence, lookupMods); var fragmentFilter = new FragmentFilter(settings.TransitionSettings, rankCharges, rankTypes).ChangeMatchAll(matchAll); if (!useFilter) { bool isProteomic = groupDocNode.TransitionGroup.IsProteomic; fragmentFilter = fragmentFilter.ChangeUseFilter(false); fragmentFilter = fragmentFilter .ChangeAdductsToDisplay(charges ?? GetRanked(fragmentFilter.RankedAdducts, isProteomic ? Transition.DEFAULT_PEPTIDE_CHARGES : Transition.DEFAULT_MOLECULE_CHARGES)); fragmentFilter = fragmentFilter.ChangeIonTypesToDisplay( types ?? GetRanked(fragmentFilter.RankedIonTypes, isProteomic ? Transition.PEPTIDE_ION_TYPES : Transition.MOLECULE_ION_TYPES)); fragmentFilter = fragmentFilter.ChangeMatchAll(true); } else { if (null != charges) { fragmentFilter = fragmentFilter.ChangeAdductsToDisplay(charges); } if (null != types) { fragmentFilter = fragmentFilter.ChangeIonTypesToDisplay(types); } } bool limitRanks = groupDocNode.IsCustomIon && // For small molecules, cap the number of ranked ions displayed if we don't have any peak metadata groupDocNode.Transitions.Any(t => string.IsNullOrEmpty(t.FragmentIonName)); if (limitRanks) { fragmentFilter = fragmentFilter.ChangeRankLimit(settings.TransitionSettings.Libraries.IonCount); } // If no library filtering will happen, return all rankings for view in the UI if (!useFilter || fragmentFilter.LibraryPick == TransitionLibraryPick.none) { if (fragmentFilter.LibraryPick == TransitionLibraryPick.none) { fragmentFilter = fragmentFilter.ChangeLibraryPick(TransitionLibraryPick.all); } fragmentFilter = fragmentFilter.ChangeFragmentMatchCount(null); } var spectrumRanker = new SpectrumRanker(targetInfo, settings, fragmentFilter); return(spectrumRanker.RankSpectrum(info, minPeaks, score)); }
public LibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroup group, SrmSettings settings, string lookupSequence, ExplicitMods lookupMods, IEnumerable <int> charges, IEnumerable <IonType> types, IEnumerable <int> rankCharges, IEnumerable <IonType> rankTypes) : this(info, labelType, group, settings, lookupSequence, lookupMods, charges, types, rankCharges, rankTypes, false, true, -1) { }
public LibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroupDocNode group, SrmSettings settings, Target lookupSequence, ExplicitMods lookupMods, IEnumerable <Adduct> charges, IEnumerable <IonType> types, IEnumerable <Adduct> rankCharges, IEnumerable <IonType> rankTypes, double?score) : this(info, labelType, group, settings, lookupSequence, lookupMods, charges, types, rankCharges, rankTypes, score, false, true, -1) { }
private static LibraryRankedSpectrumInfo MakeLibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroupDocNode groupDocNode, SrmSettings settings, Target lookupSequence, ExplicitMods lookupMods, IEnumerable <Adduct> charges, IEnumerable <IonType> types, IEnumerable <Adduct> rankCharges, IEnumerable <IonType> rankTypes, double?score, bool useFilter, bool matchAll, int minPeaks) { return(SpectrumRanker.RankSpectrum(info, labelType, groupDocNode, settings, lookupSequence, lookupMods, charges, types, rankCharges, rankTypes, score, useFilter, matchAll, minPeaks)); }
public LibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroup group, SrmSettings settings, ExplicitMods lookupMods, bool useFilter, int minPeaks) : this(info, labelType, group, settings, group.Peptide.Sequence, lookupMods, null, // charges null, // types // ReadOnlyCollection enumerators are too slow, and show under a profiler settings.TransitionSettings.Filter.ProductCharges.ToArray(), settings.TransitionSettings.Filter.IonTypes.ToArray(), useFilter, false, minPeaks) { }
public LibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroupDocNode group, SrmSettings settings, ExplicitMods lookupMods, bool useFilter, int minPeaks) : this(info, labelType, group, settings, group.Peptide.Target, lookupMods, null, // charges null, // types // ReadOnlyCollection enumerators are too slow, and show under a profiler group.IsCustomIon ? settings.TransitionSettings.Filter.SmallMoleculeFragmentAdducts.ToArray() : settings.TransitionSettings.Filter.PeptideProductCharges.ToArray(), group.IsCustomIon ? settings.TransitionSettings.Filter.SmallMoleculeIonTypes.ToArray() : settings.TransitionSettings.Filter.PeptideIonTypes.ToArray(), null, useFilter, false, minPeaks) { }
public override bool TryLoadSpectrum(LibKey key, out SpectrumPeaksInfo spectrum) { BiblioSpectrumInfo info; if (_dictLibrary != null && _dictLibrary.TryGetValue(key, out info)) { spectrum = new SpectrumPeaksInfo(ReadSpectrum(info)); return(true); } spectrum = null; return(false); }
public override bool TryLoadSpectrum(LibKey key, out SpectrumPeaksInfo spectrum) { if (_dictLibrary != null) { foreach (var item in _dictLibrary.ItemsMatching(key.LibraryKey, true)) { spectrum = new SpectrumPeaksInfo(ReadSpectrum(item)); return(true); } } spectrum = null; return(false); }
public PrositMS2Spectrum(SrmSettings settings, PrositIntensityModel.PeptidePrecursorNCE peptidePrecursorNCE, int precursorIndex, PrositIntensityModel.PrositIntensityOutput prositIntensityOutput, IsotopeLabelType labelTypeOverride = null) { PeptidePrecursorNCE = peptidePrecursorNCE; Settings = settings; var precursor = peptidePrecursorNCE.NodeGroup; var peptide = peptidePrecursorNCE.NodePep; var calc = settings.GetFragmentCalc(IsotopeLabelType.light, peptide.ExplicitMods); var ionTable = calc.GetFragmentIonMasses(peptide.Target); // TODO: get mods and pass them as explicit mods above? var ions = ionTable.GetLength(1); var mis = new List <SpectrumPeaksInfo.MI>(ions * PrositConstants.IONS_PER_RESIDUE); for (int i = 0; i < ions; ++i) { var intensities = prositIntensityOutput.OutputRows[precursorIndex].Intensities[i].Intensities .Select(ReLu).ToArray(); var yMIs = CalcMIs(ionTable[IonType.y, ions - i - 1], intensities, 0); var bMIs = CalcMIs(ionTable[IonType.b, i], intensities, PrositConstants.IONS_PER_RESIDUE / 2); mis.AddRange(yMIs); mis.AddRange(bMIs); } var maxIntensity = mis.Max(mi => mi.Intensity); // Max Norm for (int i = 0; i < mis.Count; ++i) { mis[i] = new SpectrumPeaksInfo.MI { Mz = mis[i].Mz, Intensity = mis[i].Intensity / maxIntensity } } ; SpectrumPeaks = new SpectrumPeaksInfo(mis.ToArray()); }
public bool TryLoadSpectrum(string sequence, int charge, ExplicitMods mods, out IsotopeLabelType type, out SpectrumPeaksInfo spectrum) { var libraries = PeptideSettings.Libraries; foreach (var typedSequence in GetTypedSequences(sequence, mods)) { var key = new LibKey(typedSequence.ModifiedSequence, charge); if (libraries.TryLoadSpectrum(key, out spectrum)) { type = typedSequence.LabelType; return true; } } type = IsotopeLabelType.light; spectrum = null; return false; }
private void GetSmallMoleculeFragments(LibKey key, TransitionGroupDocNode nodeGroupMatched, SpectrumPeaksInfo spectrum, IList <DocNode> transitionDocNodes) { // We usually don't know actual charge of fragments in the library, so just note + or - if // there are no peak annotations containing that info var fragmentCharge = key.Adduct.AdductCharge < 0 ? Adduct.M_MINUS : Adduct.M_PLUS; // Get list of possible transitions based on library spectrum var transitionsUnranked = new List <DocNode>(); foreach (var peak in spectrum.Peaks) { transitionsUnranked.Add(TransitionFromPeakAndAnnotations(key, nodeGroupMatched, fragmentCharge, peak, null)); } var nodeGroupUnranked = (TransitionGroupDocNode)nodeGroupMatched.ChangeChildren(transitionsUnranked); // Filter again, retain only those with rank info, or at least an interesting name SpectrumHeaderInfo groupLibInfo = null; var transitionRanks = new Dictionary <double, LibraryRankedSpectrumInfo.RankedMI>(); nodeGroupUnranked.GetLibraryInfo(Settings, ExplicitMods.EMPTY, true, ref groupLibInfo, transitionRanks); foreach (var ranked in transitionRanks) { transitionDocNodes.Add(TransitionFromPeakAndAnnotations(key, nodeGroupMatched, fragmentCharge, ranked.Value.MI, ranked.Value.Rank)); } // And add any unranked that have names to display foreach (var unrankedT in nodeGroupUnranked.Transitions) { var unranked = unrankedT; if (!string.IsNullOrEmpty(unranked.Transition.CustomIon.Name) && !transitionDocNodes.Any(t => t is TransitionDocNode && unranked.Transition.Equivalent(((TransitionDocNode)t).Transition))) { transitionDocNodes.Add(unranked); } } }
public override bool TryLoadSpectrum(LibKey key, out SpectrumPeaksInfo spectrum) { BiblioSpectrumInfo info; if (_dictLibrary != null && _dictLibrary.TryGetValue(key, out info)) { spectrum = new SpectrumPeaksInfo(ReadSpectrum(info)); return true; } spectrum = null; return false; }
public static ICollection <DbRefSpectraPeakAnnotations> Create(DbRefSpectra refSpectra, SpectrumPeaksInfo peaks) { List <DbRefSpectraPeakAnnotations> resultList = null; // Each peak may have more than one annotation if (peaks.Peaks.Any(p => p.Annotations != null && p.Annotations.Any(a => !SpectrumPeakAnnotation.IsNullOrEmpty(a)))) { resultList = new List <DbRefSpectraPeakAnnotations>(); var i = 0; foreach (var peak in peaks.Peaks) { if (peak.Annotations != null) { foreach (var annotation in peak.Annotations.Where(a => !SpectrumPeakAnnotation.IsNullOrEmpty(a))) { var result = new DbRefSpectraPeakAnnotations { RefSpectra = refSpectra, PeakIndex = i, Name = annotation.Ion.Name, Formula = annotation.Ion.NeutralFormula, InchiKey = annotation.Ion.AccessionNumbers.GetInChiKey(), OtherKeys = annotation.Ion.AccessionNumbers.GetNonInChiKeys(), Adduct = annotation.Ion.Adduct.ToString(), Charge = annotation.Ion.Adduct.AdductCharge, Comment = annotation.Comment, mzTheoretical = annotation.Ion.MonoisotopicMassMz, mzObserved = peak.Mz }; resultList.Add(result); } } i++; } } return(resultList); }
private static byte[] MZsToBytes(SpectrumPeaksInfo.MI[] peaks) { const int sizeMz = sizeof(double); byte[] peakMZs = new byte[peaks.Length * sizeMz]; for (int i = 0; i < peaks.Length; i++) { int offset = i * sizeMz; Array.Copy(BitConverter.GetBytes(peaks[i].Mz), 0, peakMZs, offset, sizeMz); } return peakMZs.Compress(); }
private static byte[] IntensitiesToBytes(SpectrumPeaksInfo.MI[] peaks) { const int sizeInten = sizeof(float); byte[] peakIntens = new byte[peaks.Length * sizeInten]; for (int i = 0; i < peaks.Length; i++) { int offset = i*sizeInten; Array.Copy(BitConverter.GetBytes(peaks[i].Intensity), 0, peakIntens, offset, sizeInten); } return peakIntens.Compress(); }
public bool TryLoadSpectrum(LibKey key, out SpectrumPeaksInfo spectrum) { Assume.IsTrue(IsLoaded); foreach (Library lib in _libraries) { if (lib != null && lib.TryLoadSpectrum(key, out spectrum)) return true; } spectrum = null; return false; }
private LibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroupDocNode groupDocNode, SrmSettings settings, Target lookupSequence, ExplicitMods lookupMods, IEnumerable <Adduct> charges, IEnumerable <IonType> types, IEnumerable <Adduct> rankCharges, IEnumerable <IonType> rankTypes, double?score, bool useFilter, bool matchAll, int minPeaks) { LabelType = labelType; // Avoid ReSharper multiple enumeration warning var rankChargesArray = rankCharges.ToArray(); var rankTypesArray = rankTypes.ToArray(); TransitionGroup group = groupDocNode.TransitionGroup; bool isProteomic = group.IsProteomic; if (score == null && groupDocNode.HasLibInfo && groupDocNode.LibInfo is BiblioSpecSpectrumHeaderInfo libInfo) { Score = libInfo.Score; } else { Score = score; } if (!useFilter) { if (charges == null) { charges = GetRanked(rankChargesArray, isProteomic ? Transition.DEFAULT_PEPTIDE_CHARGES : Transition.DEFAULT_MOLECULE_CHARGES); } if (types == null) { types = GetRanked(rankTypesArray, isProteomic ? Transition.PEPTIDE_ION_TYPES : Transition.MOLECULE_ION_TYPES); } matchAll = true; } bool limitRanks = groupDocNode.IsCustomIon && // For small molecules, cap the number of ranked ions displayed if we don't have any peak metadata groupDocNode.Transitions.Any(t => string.IsNullOrEmpty(t.FragmentIonName)); RankParams rp = new RankParams { sequence = lookupSequence, precursorAdduct = group.PrecursorAdduct, adducts = charges ?? rankCharges, types = types ?? rankTypes, matchAll = matchAll, rankCharges = rankChargesArray.Select(a => Math.Abs(a.AdductCharge)).ToArray(), rankTypes = rankTypesArray, // Precursor isotopes will not be included in MS/MS, if they will be filtered // from MS1 excludePrecursorIsotopes = settings.TransitionSettings.FullScan.IsEnabledMs, tranSettings = settings.TransitionSettings, rankLimit = limitRanks ? settings.TransitionSettings.Libraries.IonCount : (int?)null }; // Get necessary mass calculators and masses var calcMatchPre = settings.GetPrecursorCalc(labelType, lookupMods); var calcMatch = isProteomic ? settings.GetFragmentCalc(labelType, lookupMods) : settings.GetDefaultFragmentCalc(); var calcPredict = isProteomic ? settings.GetFragmentCalc(group.LabelType, lookupMods) : calcMatch; if (isProteomic && rp.sequence.IsProteomic) { rp.precursorMz = SequenceMassCalc.GetMZ(calcMatchPre.GetPrecursorMass(rp.sequence), rp.precursorAdduct); rp.massPreMatch = calcMatch.GetPrecursorFragmentMass(rp.sequence); rp.massesMatch = calcMatch.GetFragmentIonMasses(rp.sequence); rp.knownFragments = null; } else if (!isProteomic && !rp.sequence.IsProteomic) { string isotopicForumla; rp.precursorMz = SequenceMassCalc.GetMZ(calcMatchPre.GetPrecursorMass(rp.sequence.Molecule, null, rp.precursorAdduct, out isotopicForumla), rp.precursorAdduct); rp.massPreMatch = calcMatch.GetPrecursorFragmentMass(rp.sequence); // rp.massesMatch = calcMatch.GetFragmentIonMasses(rp.molecule); CONSIDER, for some molecule types someday? // For small molecules we can't predict fragmentation, so just use those we have // Older Resharper code inspection implementations insist on warning here // Resharper disable PossibleMultipleEnumeration var existing = groupDocNode.Transitions.Where(tran => tran.Transition.IsNonPrecursorNonReporterCustomIon()).Select(t => t.Transition.CustomIon.GetMass(MassType.Monoisotopic)).ToArray(); rp.massesMatch = new IonTable <TypedMass>(IonType.custom, existing.Length); for (var i = 0; i < existing.Length; i++) { rp.massesMatch[IonType.custom, i] = existing[i]; } // Resharper restore PossibleMultipleEnumeration rp.knownFragments = groupDocNode.Transitions.Where(tran => tran.Transition.IsNonPrecursorNonReporterCustomIon()).Select(t => new KnownFragment { Adduct = t.Transition.Adduct, Name = t.GetFragmentIonName(CultureInfo.CurrentCulture, settings.TransitionSettings.Libraries.IonMatchTolerance), Mz = t.Mz }).ToList(); } else { rp.precursorMz = 0.0; rp.massPreMatch = TypedMass.ZERO_MONO_MASSH; rp.massesMatch = IonTable <TypedMass> .EMPTY; rp.knownFragments = null; } rp.massPrePredict = rp.massPreMatch; rp.massesPredict = rp.massesMatch; if (!ReferenceEquals(calcPredict, calcMatch)) { rp.massPrePredict = calcPredict.GetPrecursorFragmentMass(rp.sequence); if (rp.sequence.IsProteomic) // CONSIDER - eventually we may be able to predict fragments for small molecules? { rp.massesPredict = calcPredict.GetFragmentIonMasses(rp.sequence); } } // Get values of interest from the settings. var tranSettings = settings.TransitionSettings; var predict = tranSettings.Prediction; var filter = tranSettings.Filter; var libraries = tranSettings.Libraries; var instrument = tranSettings.Instrument; // Get potential losses to all fragments in this peptide rp.massType = predict.FragmentMassType; rp.potentialLosses = TransitionGroup.CalcPotentialLosses(rp.sequence, settings.PeptideSettings.Modifications, lookupMods, rp.massType); // Create arrays because ReadOnlyCollection enumerators are too slow // In some cases these collections must be enumerated for every ion // allowed in the library specturm. rp.startFinder = filter.FragmentRangeFirst; rp.endFinder = filter.FragmentRangeLast; // Get library settings Tolerance = libraries.IonMatchTolerance; rp.tolerance = Tolerance; rp.pick = tranSettings.Libraries.Pick; int ionMatchCount = libraries.IonCount; // If no library filtering will happen, return all rankings for view in the UI if (!useFilter || rp.pick == TransitionLibraryPick.none) { if (rp.pick == TransitionLibraryPick.none) { rp.pick = TransitionLibraryPick.all; } ionMatchCount = -1; } // Get instrument settings rp.minMz = instrument.MinMz; rp.maxMz = instrument.MaxMz; // Get the library spectrum mass-intensity pairs IList <SpectrumPeaksInfo.MI> listMI = info.Peaks; // Because sorting and matching observed ions with predicted // ions appear as bottlenecks in a profiler, a minimum number // of peaks may be supplied to allow the use of a 2-phase linear // filter that can significantly reduce the number of peaks // needing the O(n*log(n)) sorting and the O(n*m) matching. int len = listMI.Count; float intensityCutoff = 0; if (minPeaks != -1) { // Start searching for good cut-off at mean intensity. double totalIntensity = info.Intensities.Sum(); FindIntensityCutoff(listMI, 0, (float)(totalIntensity / len) * 2, minPeaks, 1, ref intensityCutoff, ref len); } // Create filtered peak array storing original index for m/z ordering // to avoid needing to sort to return to this order. RankedMI[] arrayRMI = new RankedMI[len]; // Detect when m/z values are out of order, and use the expensive sort // by m/z to correct this. double lastMz = double.MinValue; bool sortMz = false; for (int i = 0, j = 0, lenOrig = listMI.Count; i < lenOrig; i++) { SpectrumPeaksInfo.MI mi = listMI[i]; if (mi.Intensity >= intensityCutoff || intensityCutoff == 0) { arrayRMI[j] = new RankedMI(mi, j); j++; } if (ionMatchCount == -1) { if (mi.Mz < lastMz) { sortMz = true; } lastMz = mi.Mz; } } // The one expensive sort is used to determine rank order // by intensity, or m/z in case of a tie. Array.Sort(arrayRMI, OrderIntensityDesc); RankedMI[] arrayResult = new RankedMI[ionMatchCount != -1 ? ionMatchCount : arrayRMI.Length]; foreach (RankedMI rmi in arrayRMI) { rmi.CalculateRank(rp); // If not filtering for only the highest ionMatchCount ranks if (ionMatchCount == -1) { // Put the ranked record back where it started in the // m/z ordering to avoid a second sort. arrayResult[rmi.IndexMz] = rmi; } // Otherwise, if this ion was ranked, add it to the result array else if (rmi.Rank > 0) { int countRanks = rmi.Rank; arrayResult[countRanks - 1] = rmi; // And stop when the array is full if (countRanks == ionMatchCount) { break; } } } // Is this a theoretical library with no intensity variation? If so it can't be ranked. // If it has any interesting peak annotations, pass those through if (rp.Ranked == 0 && arrayRMI.All(rmi => rmi.Intensity == arrayRMI[0].Intensity)) { // Only do this if we have been asked to limit the ions matched, and there are any annotations if (ionMatchCount != -1 && arrayRMI.Any(rmi => rmi.HasAnnotations)) { // Pass through anything with an annotation as being of probable interest arrayResult = arrayRMI.Where(rmi => rmi.HasAnnotations).ToArray(); ionMatchCount = -1; } } // If not enough ranked ions were found, fill the rest of the results array if (ionMatchCount != -1) { for (int i = rp.Ranked; i < ionMatchCount; i++) { arrayResult[i] = RankedMI.EMPTY; } } // If all ions are to be included, and some were found out of order, then // the expensive full sort by m/z is necesary. else if (sortMz) { Array.Sort(arrayResult, OrderMz); } _spectrum = MakeReadOnly(arrayResult); }
private LibraryRankedSpectrumInfo(SpectrumPeaksInfo info, IsotopeLabelType labelType, TransitionGroup group, SrmSettings settings, string lookupSequence, ExplicitMods lookupMods, IEnumerable <int> charges, IEnumerable <IonType> types, IEnumerable <int> rankCharges, IEnumerable <IonType> rankTypes, bool useFilter, bool matchAll, int minPeaks) { LabelType = labelType; // Avoid ReSharper multiple enumeration warning var rankChargesArray = rankCharges.ToArray(); var rankTypesArray = rankTypes.ToArray(); if (!useFilter) { if (charges == null) { charges = GetRanked(rankChargesArray, Transition.ALL_CHARGES); } if (types == null) { types = GetRanked(rankTypesArray, Transition.ALL_TYPES); } matchAll = true; } RankParams rp = new RankParams { sequence = lookupSequence, precursorCharge = group.PrecursorCharge, charges = charges ?? rankCharges, types = types ?? rankTypes, matchAll = matchAll, rankCharges = rankChargesArray, rankTypes = rankTypesArray, // Precursor isotopes will not be included in MS/MS, if they will be filtered // from MS1 excludePrecursorIsotopes = settings.TransitionSettings.FullScan.IsEnabledMs, tranSettings = settings.TransitionSettings }; // Get necessary mass calculators and masses var calcMatchPre = settings.GetPrecursorCalc(labelType, lookupMods); var calcMatch = settings.GetFragmentCalc(labelType, lookupMods); var calcPredict = settings.GetFragmentCalc(group.LabelType, lookupMods); if (!string.IsNullOrEmpty(rp.sequence)) { rp.precursorMz = SequenceMassCalc.GetMZ(calcMatchPre.GetPrecursorMass(rp.sequence), rp.precursorCharge); rp.massPreMatch = calcMatch.GetPrecursorFragmentMass(rp.sequence); rp.massesMatch = calcMatch.GetFragmentIonMasses(rp.sequence); } else { rp.precursorMz = 0.0; rp.massPreMatch = 0.0; rp.massesMatch = new double[0, 0]; } rp.massPrePredict = rp.massPreMatch; rp.massesPredict = rp.massesMatch; if (!ReferenceEquals(calcPredict, calcMatch) && !string.IsNullOrEmpty(rp.sequence)) { rp.massPrePredict = calcPredict.GetPrecursorFragmentMass(rp.sequence); rp.massesPredict = calcPredict.GetFragmentIonMasses(rp.sequence); } // Get values of interest from the settings. var tranSettings = settings.TransitionSettings; var predict = tranSettings.Prediction; var filter = tranSettings.Filter; var libraries = tranSettings.Libraries; var instrument = tranSettings.Instrument; // Get potential losses to all fragments in this peptide rp.massType = predict.FragmentMassType; rp.potentialLosses = TransitionGroup.CalcPotentialLosses(rp.sequence, settings.PeptideSettings.Modifications, lookupMods, rp.massType); // Create arrays because ReadOnlyCollection enumerators are too slow // In some cases these collections must be enumerated for every ion // allowed in the library specturm. rp.startFinder = filter.FragmentRangeFirst; rp.endFinder = filter.FragmentRangeLast; // Get library settings Tolerance = libraries.IonMatchTolerance; rp.tolerance = Tolerance; rp.pick = tranSettings.Libraries.Pick; int ionMatchCount = libraries.IonCount; // If no library filtering will happen, return all rankings for view in the UI if (!useFilter || rp.pick == TransitionLibraryPick.none) { if (rp.pick == TransitionLibraryPick.none) { rp.pick = TransitionLibraryPick.all; } ionMatchCount = -1; } // Get instrument settings rp.minMz = instrument.MinMz; rp.maxMz = instrument.MaxMz; // Get the library spectrum mass-intensity pairs IList <SpectrumPeaksInfo.MI> listMI = info.Peaks; // Because sorting and matching observed ions with predicted // ions appear as bottlenecks in a profiler, a minimum number // of peaks may be supplied to allow the use of a 2-phase linear // filter that can significantly reduce the number of peaks // needing the O(n*log(n)) sorting and the O(n*m) matching. int len = listMI.Count; float intensityCutoff = 0; if (minPeaks != -1) { // Start searching for good cut-off at mean intensity. double totalIntensity = info.Intensities.Sum(); FindIntensityCutoff(listMI, 0, (float)(totalIntensity / len) * 2, minPeaks, 1, ref intensityCutoff, ref len); } // Create filtered peak array storing original index for m/z ordering // to avoid needing to sort to return to this order. RankedMI[] arrayRMI = new RankedMI[len]; // Detect when m/z values are out of order, and use the expensive sort // by m/z to correct this. double lastMz = double.MinValue; bool sortMz = false; for (int i = 0, j = 0, lenOrig = listMI.Count; i < lenOrig; i++) { SpectrumPeaksInfo.MI mi = listMI[i]; if (mi.Intensity >= intensityCutoff || intensityCutoff == 0) { arrayRMI[j] = new RankedMI(mi, j); j++; } if (ionMatchCount == -1) { if (mi.Mz < lastMz) { sortMz = true; } lastMz = mi.Mz; } } // The one expensive sort is used to determine rank order // by intensity. Array.Sort(arrayRMI, OrderIntensityDesc); RankedMI[] arrayResult = new RankedMI[ionMatchCount != -1 ? ionMatchCount : arrayRMI.Length]; foreach (RankedMI rmi in arrayRMI) { rmi.CalculateRank(rp); // If not filtering for only the highest ionMatchCount ranks if (ionMatchCount == -1) { // Put the ranked record back where it started in the // m/z ordering to avoid a second sort. arrayResult[rmi.IndexMz] = rmi; } // Otherwise, if this ion was ranked, add it to the result array else if (rmi.Rank > 0) { int countRanks = rmi.Rank; arrayResult[countRanks - 1] = rmi; // And stop when the array is full if (countRanks == ionMatchCount) { break; } } } // If not enough ranked ions were found, fill the rest of the results array if (ionMatchCount != -1) { for (int i = rp.Ranked; i < ionMatchCount; i++) { arrayResult[i] = RankedMI.EMPTY; } } // If all ions are to be included, and some were found out of order, then // the expensive full sort by m/z is necesary. else if (sortMz) { Array.Sort(arrayResult, OrderMz); } _spectrum = MakeReadOnly(arrayResult); }
public void UpdateUI(bool selectionChanged = true) { // Only worry about updates, if the graph is visible // And make sure it is not disposed, since rendering happens on a timer if (!Visible || IsDisposed) { return; } // Clear existing data from the graph pane var graphPane = (MSGraphPane)graphControl.MasterPane[0]; graphPane.CurveList.Clear(); graphPane.GraphObjList.Clear(); GraphItem = null; GraphHelper.FormatGraphPane(graphControl.GraphPane); GraphHelper.FormatFontSize(graphControl.GraphPane, Settings.Default.SpectrumFontSize); // Try to find a tree node with spectral library info associated // with the current selection. var nodeTree = _stateProvider.SelectedNode as SrmTreeNode; var nodeGroupTree = nodeTree as TransitionGroupTreeNode; var nodeTranTree = nodeTree as TransitionTreeNode; if (nodeTranTree != null) { nodeGroupTree = nodeTranTree.Parent as TransitionGroupTreeNode; } var nodeGroup = (nodeGroupTree != null ? nodeGroupTree.DocNode : null); PeptideTreeNode nodePepTree; if (nodeGroup == null) { nodePepTree = nodeTree as PeptideTreeNode; if (nodePepTree != null) { var listInfoGroups = GetLibraryInfoChargeGroups(nodePepTree); if (listInfoGroups.Length == 1) { nodeGroup = listInfoGroups[0]; } else if (listInfoGroups.Length > 1) { _nodeGroup = null; toolBar.Visible = false; _graphHelper.SetErrorGraphItem(new NoDataMSGraphItem( Resources.GraphSpectrum_UpdateUI_Multiple_charge_states_with_library_spectra)); return; } } } else { nodePepTree = nodeGroupTree.Parent as PeptideTreeNode; } // Check for appropriate spectrum to load SrmSettings settings = DocumentUI.Settings; PeptideLibraries libraries = settings.PeptideSettings.Libraries; bool available = false; if (nodeGroup == null || (!nodeGroup.HasLibInfo && !libraries.HasMidasLibrary)) { _spectra = null; } else { TransitionGroup group = nodeGroup.TransitionGroup; TransitionDocNode transition = (nodeTranTree == null ? null : nodeTranTree.DocNode); var lookupSequence = group.Peptide.Target;// Sequence or custom ion id ExplicitMods lookupMods = null; if (nodePepTree != null) { lookupSequence = nodePepTree.DocNode.SourceUnmodifiedTarget; lookupMods = nodePepTree.DocNode.SourceExplicitMods; } try { // Try to load a list of spectra matching the criteria for // the current node group. if (libraries.HasLibraries && libraries.IsLoaded) { if (NodeGroupChanged(nodeGroup)) { try { UpdateSpectra(nodeGroup, lookupSequence, lookupMods); UpdateToolbar(); } catch (Exception) { _spectra = null; UpdateToolbar(); throw; } _nodeGroup = nodeGroup; if (settings.TransitionSettings.Instrument.IsDynamicMin) { ZoomSpectrumToSettings(); } } var spectrum = SelectedSpectrum; if (spectrum != null) { IsotopeLabelType typeInfo = spectrum.LabelType; var types = _stateProvider.ShowIonTypes(group.IsProteomic); var adducts = (group.IsProteomic ? Transition.DEFAULT_PEPTIDE_LIBRARY_CHARGES : nodeGroup.InUseAdducts).ToArray(); var charges = _stateProvider.ShowIonCharges(adducts); var rankTypes = group.IsProteomic ? settings.TransitionSettings.Filter.PeptideIonTypes : settings.TransitionSettings.Filter.SmallMoleculeIonTypes; var rankAdducts = group.IsProteomic ? settings.TransitionSettings.Filter.PeptideProductCharges : settings.TransitionSettings.Filter.SmallMoleculeFragmentAdducts; var rankCharges = Adduct.OrderedAbsoluteChargeValues(rankAdducts); // Make sure the types and charges in the settings are at the head // of these lists to give them top priority, and get rankings correct. int i = 0; foreach (IonType type in rankTypes) { if (types.Remove(type)) { types.Insert(i++, type); } } i = 0; var showAdducts = new List <Adduct>(); foreach (var charge in rankCharges) { if (charges.Remove(charge)) { charges.Insert(i++, charge); } // NB for all adducts we just look at abs value of charge // CONSIDER(bspratt): we may want finer per-adduct control for small molecule use showAdducts.AddRange(adducts.Where(a => charge == Math.Abs(a.AdductCharge))); } showAdducts.AddRange(adducts.Where(a => charges.Contains(Math.Abs(a.AdductCharge)) && !showAdducts.Contains(a))); SpectrumPeaksInfo spectrumInfo = spectrum.SpectrumPeaksInfo; var spectrumInfoR = new LibraryRankedSpectrumInfo(spectrumInfo, typeInfo, nodeGroup, settings, lookupSequence, lookupMods, showAdducts, types, rankAdducts, rankTypes); GraphItem = new SpectrumGraphItem(nodeGroup, transition, spectrumInfoR, spectrum.LibName) { ShowTypes = types, ShowCharges = charges, ShowRanks = Settings.Default.ShowRanks, ShowMz = Settings.Default.ShowIonMz, ShowObservedMz = Settings.Default.ShowObservedMz, ShowDuplicates = Settings.Default.ShowDuplicateIons, FontSize = Settings.Default.SpectrumFontSize, LineWidth = Settings.Default.SpectrumLineWidth }; LibraryChromGroup chromatogramData = null; if (Settings.Default.ShowLibraryChromatograms) { chromatogramData = spectrum.LoadChromatogramData(); } if (null == chromatogramData) { _graphHelper.ResetForSpectrum(new[] { nodeGroup.TransitionGroup }); _graphHelper.AddSpectrum(GraphItem); _graphHelper.ZoomSpectrumToSettings(DocumentUI, nodeGroup); } else { _graphHelper.ResetForChromatograms(new[] { nodeGroup.TransitionGroup }); var displayType = GraphChromatogram.GetDisplayType(DocumentUI, nodeGroup); IList <TransitionDocNode> displayTransitions = GraphChromatogram.GetDisplayTransitions(nodeGroup, displayType).ToArray(); int numTrans = displayTransitions.Count; var allChromDatas = chromatogramData.ChromDatas.Where( chromData => DisplayTypeMatches(chromData, displayType)).ToList(); var chromDatas = new List <LibraryChromGroup.ChromData>(); for (int iTran = 0; iTran < numTrans; iTran++) { var displayTransition = displayTransitions[iTran]; var indexMatch = allChromDatas.IndexOf(chromData => IonMatches(displayTransition.Transition, chromData)); if (indexMatch >= 0) { chromDatas.Add(allChromDatas[indexMatch]); allChromDatas.RemoveAt(indexMatch); } else { chromDatas.Add(null); } } allChromDatas.Sort((chromData1, chromData2) => chromData1.Mz.CompareTo(chromData2.Mz)); chromDatas.AddRange(allChromDatas); double maxHeight = chromDatas.Max(chromData => null == chromData ? double.MinValue : chromData.Height); int iChromDataPrimary = chromDatas.IndexOf(chromData => null != chromData && maxHeight == chromData.Height); int colorOffset = displayType == DisplayTypeChrom.products ? GraphChromatogram.GetDisplayTransitions(nodeGroup, DisplayTypeChrom. precursors).Count() : 0; for (int iChromData = 0; iChromData < chromDatas.Count; iChromData++) { var chromData = chromDatas[iChromData]; if (chromData == null) { continue; } string label; var pointAnnotation = GraphItem.AnnotatePoint(new PointPair(chromData.Mz, 1.0)); if (null != pointAnnotation) { label = pointAnnotation.Label; } else { label = chromData.Mz.ToString(@"0.####"); } TransitionDocNode matchingTransition; Color color; if (iChromData < numTrans) { matchingTransition = displayTransitions[iChromData]; color = GraphChromatogram.COLORS_LIBRARY[ (iChromData + colorOffset) % GraphChromatogram.COLORS_LIBRARY.Count]; } else { matchingTransition = null; color = GraphChromatogram.COLORS_GROUPS[ iChromData % GraphChromatogram.COLORS_GROUPS.Count]; } TransitionChromInfo tranPeakInfo; ChromatogramInfo chromatogramInfo; MakeChromatogramInfo(nodeGroup.PrecursorMz, chromatogramData, chromData, out chromatogramInfo, out tranPeakInfo); var graphItem = new ChromGraphItem(nodeGroup, matchingTransition, chromatogramInfo, iChromData == iChromDataPrimary ? tranPeakInfo : null, null, new[] { iChromData == iChromDataPrimary }, null, 0, false, false, null, 0, color, Settings.Default.ChromatogramFontSize, 1); LineItem curve = (LineItem)_graphHelper.AddChromatogram(PaneKey.DEFAULT, graphItem); if (matchingTransition == null) { curve.Label.Text = label; } curve.Line.Width = Settings.Default.ChromatogramLineWidth; if (null != transition) { if (IonMatches(transition.Transition, chromData)) { color = ChromGraphItem.ColorSelected; } } curve.Color = color; } graphPane.Title.IsVisible = false; graphPane.Legend.IsVisible = true; _graphHelper.FinishedAddingChromatograms(chromatogramData.StartTime, chromatogramData.EndTime, false); graphControl.Refresh(); } graphControl.IsEnableVPan = graphControl.IsEnableVZoom = !Settings.Default.LockYAxis; available = true; } } } catch (Exception) { _graphHelper.SetErrorGraphItem(new NoDataMSGraphItem( Resources.GraphSpectrum_UpdateUI_Failure_loading_spectrum__Library_may_be_corrupted)); return; } } // Show unavailable message, if no spectrum loaded if (!available) { UpdateToolbar(); _nodeGroup = null; _graphHelper.SetErrorGraphItem(new UnavailableMSGraphItem()); } }
public LibraryRankedSpectrumInfo RankSpectrum(SpectrumPeaksInfo info, int minPeaks, double?score) { var ionsToReturn = FragmentFilterObj.FragmentMatchCount; RankingState rankingState = new RankingState() { matchAll = MatchAll, }; // Get the library spectrum mass-intensity pairs IList <SpectrumPeaksInfo.MI> listMI = info.Peaks; // Because sorting and matching observed ions with predicted // ions appear as bottlenecks in a profiler, a minimum number // of peaks may be supplied to allow the use of a 2-phase linear // filter that can significantly reduce the number of peaks // needing the O(n*log(n)) sorting and the O(n*m) matching. int len = listMI.Count; float intensityCutoff = 0; if (minPeaks != -1) { // Start searching for good cut-off at mean intensity. double totalIntensity = info.Intensities.Sum(); FindIntensityCutoff(listMI, 0, (float)(totalIntensity / len) * 2, minPeaks, 1, ref intensityCutoff, ref len); } // Create filtered peak array storing original index for m/z ordering // to avoid needing to sort to return to this order. RankedMI[] arrayRMI = new RankedMI[len]; // Detect when m/z values are out of order, and use the expensive sort // by m/z to correct this. double lastMz = double.MinValue; bool sortMz = false; for (int i = 0, j = 0, lenOrig = listMI.Count; i < lenOrig; i++) { SpectrumPeaksInfo.MI mi = listMI[i]; if (mi.Intensity >= intensityCutoff || intensityCutoff == 0) { arrayRMI[j] = new RankedMI(mi, j); j++; } if (!ionsToReturn.HasValue) { if (mi.Mz < lastMz) { sortMz = true; } lastMz = mi.Mz; } } // The one expensive sort is used to determine rank order // by intensity, or m/z in case of a tie. Array.Sort(arrayRMI, OrderIntensityDesc); RankedMI[] arrayResult = new RankedMI[ionsToReturn.HasValue ? ionsToReturn.Value : arrayRMI.Length]; foreach (RankedMI rmi in arrayRMI) { var rankedRmi = CalculateRank(rankingState, rmi); // If not filtering for only the highest ionMatchCount ranks if (!ionsToReturn.HasValue) { // Put the ranked record back where it started in the // m/z ordering to avoid a second sort. arrayResult[rmi.IndexMz] = rankedRmi; } // Otherwise, if this ion was ranked, add it to the result array else if (rankedRmi.Rank > 0) { int countRanks = rankedRmi.Rank; arrayResult[countRanks - 1] = rankedRmi; // And stop when the array is full if (countRanks == ionsToReturn.Value) { break; } } } // Is this a theoretical library with no intensity variation? If so it can't be ranked. // If it has any interesting peak annotations, pass those through if (rankingState.Ranked == 0 && arrayRMI.All(rmi => rmi.Intensity == arrayRMI[0].Intensity)) { // Only do this if we have been asked to limit the ions matched, and there are any annotations if (ionsToReturn.HasValue && arrayRMI.Any(rmi => rmi.HasAnnotations)) { // Pass through anything with an annotation as being of probable interest arrayResult = arrayRMI.Where(rmi => rmi.HasAnnotations).ToArray(); ionsToReturn = null; } } // If not enough ranked ions were found, fill the rest of the results array if (ionsToReturn.HasValue) { for (int i = rankingState.Ranked; i < ionsToReturn.Value; i++) { arrayResult[i] = RankedMI.EMPTY; } } // If all ions are to be included, and some were found out of order, then // the expensive full sort by m/z is necessary. else if (sortMz) { Array.Sort(arrayResult, OrderMz); } double?spectrumScore; if (score == null && GroupDocNode.HasLibInfo && GroupDocNode.LibInfo is BiblioSpecSpectrumHeaderInfo libInfo) { spectrumScore = libInfo.Score; } else { spectrumScore = score; } return(new LibraryRankedSpectrumInfo(PredictLabelType, Libraries.IonMatchTolerance, arrayResult, spectrumScore)); }