Ejemplo n.º 1
0
        private SpectrumPeaksInfo.MI[] ReadSpectrum(BiblioSpectrumInfo info)
        {
            const int lenPair = sizeof(float) + sizeof(float);

            byte[] peaks = new byte[info.NumPeaks * lenPair];
            lock (ReadStream)
            {
                Stream fs = ReadStream.Stream;

                // Seek to stored location
                fs.Seek(info.Location, SeekOrigin.Begin);

                // Single read to get all the peaks
                if (fs.Read(peaks, 0, peaks.Length) < peaks.Length)
                {
                    throw new IOException(Resources.BiblioSpecLibrary_ReadSpectrum_Failure_trying_to_read_peaks);
                }
            }

            // Build the list
            var arrayMI = new SpectrumPeaksInfo.MI[info.NumPeaks];

            for (int i = 0, iNext = 0; i < peaks.Length; i += lenPair)
            {
                arrayMI[iNext].Intensity = BitConverter.ToSingle(peaks, i + sizeof(Single));
                arrayMI[iNext++].Mz      = BitConverter.ToSingle(peaks, i);
            }

            return(arrayMI);
        }
Ejemplo n.º 2
0
        protected override SpectrumPeaksInfo.MI[] ReadSpectrum(XHunterSpectrumInfo info)
        {
            const int lenPair = sizeof(byte) + sizeof(float);

            byte[] peaks = new byte[info.NumPeaks * lenPair];

            lock (ReadStream)
            {
                try
                {
                    Stream fs = ReadStream.Stream;

                    // Seek to stored location
                    fs.Seek(info.Location, SeekOrigin.Begin);

                    // Single read to get all the peaks
                    if (fs.Read(peaks, 0, peaks.Length) < peaks.Length)
                    {
                        throw new IOException(Resources.XHunterLibrary_ReadSpectrum_Failure_trying_to_read_peaks);
                    }
                }
                catch (Exception)
                {
                    // If an exception is thrown, close the stream in case the failure is something
                    // like a network failure that can be remedied by re-opening the stream.
                    ReadStream.CloseStream();
                    throw;
                }
            }

            // Build the list
            var arrayMI = new SpectrumPeaksInfo.MI[info.NumPeaks];

            // Read intensities
            for (int i = 0; i < info.NumPeaks; i++)
            {
                arrayMI[i].Intensity = peaks[i];
            }
            // Read m/z values
            for (int i = info.NumPeaks, iNext = 0; i < peaks.Length; i += sizeof(float))
            {
                arrayMI[iNext++].Mz = BitConverter.ToSingle(peaks, i);
            }

            return(arrayMI);
        }
Ejemplo n.º 3
0
        private void PeakAnnotationsTest()
        {
            // Verify an operation that could break if SpectrumPeaksInfo.MI changes from struct to class
            var existingAnnotations = new List <SpectrumPeakAnnotation>
            {
                SpectrumPeakAnnotation.Create(new CustomIon(new CustomMolecule("C12H5N6", "foo"), Adduct.M_MINUS), "commentFoo")
            };
            var existing = new SpectrumPeaksInfo.MI {
                Intensity = 111, Mz = 222, Annotations = existingAnnotations
            };
            var combined = new List <SpectrumPeakAnnotation>();

            foreach (var spectrumPeakAnnotation in existing.Annotations)
            {
                combined.Add(spectrumPeakAnnotation);
            }
            combined.Add(SpectrumPeakAnnotation.Create(new CustomIon(new CustomMolecule("C12H5N7", "bar"), Adduct.M_MINUS), "commentBar"));
            var updated = existing.ChangeAnnotations(combined);

            Assume.IsTrue(!Equals(existing, updated)); // This may fail if SpectrumPeaksInfo.MI changes from struct to class
        }
        private string NoteIfAnnotationMzDisagrees(LibKey key, SpectrumPeaksInfo.MI peak)
        {
            foreach (var peakAnnotation in peak.GetAnnotationsEnumerator())
            {
                var charge           = peakAnnotation.Ion.Adduct;
                var monoisotopicMass = charge.MassFromMz(peak.Mz, MassType.Monoisotopic);
                var averageMass      = charge.MassFromMz(peak.Mz, MassType.Average);

                if (!(peakAnnotation.Ion.MonoisotopicMass.Equals(monoisotopicMass,
                                                                 Settings.TransitionSettings.Instrument.MzMatchTolerance) ||
                      peakAnnotation.Ion.AverageMass.Equals(averageMass,
                                                            Settings.TransitionSettings.Instrument.MzMatchTolerance)))
                {
                    return(string.Format(
                               @"annotated observed ({0}) and theoretical ({1}) masses differ for peak {2} of library entry {3} by more than the current instrument mz match tolerance of {4}",
                               peak.Mz, peakAnnotation.Ion.MonoisotopicMassMz, peakAnnotation,
                               key,
                               Settings.TransitionSettings.Instrument.MzMatchTolerance));
                }
            }
            return(null);
        }
Ejemplo n.º 5
0
        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());
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Test only method for creating a <see cref="XHunterLibrary"/> file
        /// from another loaded <see cref="Library"/>.  Should this move into test project?
        /// </summary>
        /// <param name="streamManager">Provides access to the file system</param>
        /// <param name="path">Path to write to</param>
        /// <param name="library">The loaded library to use as a data source</param>
        /// <param name="lowIntensity">True to use 20 lowest intensity peaks for bad spectrum</param>
        public static void Write(IStreamManager streamManager, string path, Library library, bool lowIntensity)
        {
            using (FileSaver fs = new FileSaver(path, streamManager))
                using (Stream outStream = streamManager.CreateStream(fs.SafeName, FileMode.Create, true))
                {
                    outStream.Write(BitConverter.GetBytes(0), 0, sizeof(int));
                    outStream.Write(BitConverter.GetBytes(library.SpectrumCount), 0, sizeof(int));

                    byte[]       header     = new byte[256 - 8];
                    const string headerText = @"HLF v=2 s=test.hlf d=2009.02.04";
                    Encoding.UTF8.GetBytes(headerText, 0, headerText.Length, header, 0);

                    outStream.Write(header, 0, header.Length);

                    SequenceMassCalc calc = new SequenceMassCalc(MassType.Monoisotopic);

                    byte[] seqBuffer = new byte[1024];

                    foreach (var key in library.Keys)
                    {
                        SpectrumPeaksInfo peaksInfo;
                        if (!library.TryLoadSpectrum(key, out peaksInfo))
                        {
                            continue;
                        }

                        // Fake X! Hunter filtering by choosing just the to 20 peaks
                        SpectrumPeaksInfo.MI[] peaks = peaksInfo.Peaks.ToArray();
                        // Sort by intensity
                        if (lowIntensity)
                        {
                            Array.Sort(peaks, (p1, p2) => Comparer.Default.Compare(p1.Intensity, p2.Intensity)); // ascending
                        }
                        else
                        {
                            Array.Sort(peaks, (p1, p2) => Comparer.Default.Compare(p2.Intensity, p1.Intensity)); // descending
                        }
                        float maxI = peaks.Length == 0 ? 0 : peaks[0].Intensity;
                        // Take 20 most intense peaks
                        SpectrumPeaksInfo.MI[] peaksFiltered = new SpectrumPeaksInfo.MI[Math.Min(20, peaks.Length)];
                        Array.Copy(peaks, peaksFiltered, peaksFiltered.Length);
                        // Resort by m/z (ineffient, but this is test code)
                        Array.Sort(peaksFiltered, (p1, p2) => Comparer.Default.Compare(p1.Mz, p2.Mz));

                        double totalI    = 0;
                        byte[] peakBytes = new byte[(sizeof(byte) + sizeof(float)) * peaksFiltered.Length];
                        for (int i = 0; i < peaksFiltered.Length; i++)
                        {
                            var mi = peaksFiltered[i];

                            // Calculate the X! Hunter processed intensity value
                            float intensity = 100f * mi.Intensity / maxI;
                            totalI += intensity;

                            // Fill the peaks buffer
                            peakBytes[i] = (byte)(int)intensity;
                            Array.Copy(BitConverter.GetBytes((float)mi.Mz), 0, peakBytes, peaksFiltered.Length + i * 4, sizeof(float));
                        }

                        var sequence = key.Target.ToString();
                        // Only works for unmodified sequence
                        Debug.Assert(!key.IsModified);
                        double precursorMH = calc.GetPrecursorMass(sequence);
                        outStream.Write(BitConverter.GetBytes(precursorMH), 0, sizeof(double));
                        outStream.Write(BitConverter.GetBytes(key.Charge), 0, sizeof(int));
                        // Value rounded for consistent serialization round-tripping
                        float i2 = (float)Math.Round(Math.Sqrt(totalI), 4);
                        outStream.Write(BitConverter.GetBytes(i2), 0, sizeof(float));
                        outStream.Write(BitConverter.GetBytes(0.0001f), 0, sizeof(float));
                        outStream.Write(BitConverter.GetBytes(sequence.Length), 0, sizeof(int));

                        // Sequence
                        Encoding.UTF8.GetBytes(sequence, 0, sequence.Length, seqBuffer, 0);
                        outStream.Write(seqBuffer, 0, sequence.Length);

                        // Peaks
                        outStream.Write(BitConverter.GetBytes(peaksFiltered.Length), 0, sizeof(int));
                        outStream.Write(peakBytes, 0, peakBytes.Length);

                        // Modifications
                        outStream.Write(BitConverter.GetBytes(0), 0, sizeof(int));
                        // Homologs
                        outStream.Write(BitConverter.GetBytes(0), 0, sizeof(int));
                    }

                    streamManager.Finish(outStream);
                    fs.Commit();
                }
        }
Ejemplo n.º 7
0
            public RankedMI(SpectrumPeaksInfo.MI mi, int indexMz)
            {
                _mi = mi;

                IndexMz = indexMz;
            }
Ejemplo n.º 8
0
        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 TransitionDocNode TransitionFromPeakAndAnnotations(LibKey key, TransitionGroupDocNode nodeGroup,
                                                                   Adduct fragmentCharge, SpectrumPeaksInfo.MI peak, int?rank)
        {
            var charge           = fragmentCharge;
            var monoisotopicMass = charge.MassFromMz(peak.Mz, MassType.Monoisotopic);
            var averageMass      = charge.MassFromMz(peak.Mz, MassType.Average);
            // Caution here - library peak (observed) mz may not exactly match (theoretical) mz of the annotation

            // In the case of multiple annotations, produce single transition for display in library explorer
            var annotations = peak.GetAnnotationsEnumerator().ToArray();
            var spectrumPeakAnnotationIon = peak.AnnotationsAggregateDescriptionIon;
            var molecule = spectrumPeakAnnotationIon.Adduct.IsEmpty
                ? new CustomMolecule(monoisotopicMass, averageMass)
                : spectrumPeakAnnotationIon;
            var note = (annotations.Length > 1) ? TextUtil.LineSeparate(annotations.Select(a => a.ToString())) : null;
            var noteIfAnnotationMzDisagrees = NoteIfAnnotationMzDisagrees(key, peak);

            if (noteIfAnnotationMzDisagrees != null)
            {
                if (note == null)
                {
                    note = noteIfAnnotationMzDisagrees;
                }
                else
                {
                    note = TextUtil.LineSeparate(note, noteIfAnnotationMzDisagrees);
                }
            }
            var transition = new Transition(nodeGroup.TransitionGroup,
                                            spectrumPeakAnnotationIon.Adduct.IsEmpty ? charge : spectrumPeakAnnotationIon.Adduct, 0, molecule);

            return(new TransitionDocNode(transition, Annotations.EMPTY.ChangeNote(note), null, monoisotopicMass,
                                         rank.HasValue ?
                                         new TransitionDocNode.TransitionQuantInfo(null,
                                                                                   new TransitionLibInfo(rank.Value, peak.Intensity), true) :
                                         TransitionDocNode.TransitionQuantInfo.DEFAULT, ExplicitTransitionValues.EMPTY, null));
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        private SpectrumPeaksInfo.MI[] ReadSpectrum(BiblioSpectrumInfo info)
        {
            const int lenPair = sizeof(float) + sizeof(float);
            byte[] peaks = new byte[info.NumPeaks * lenPair];
            lock (ReadStream)
            {
                Stream fs = ReadStream.Stream;

                // Seek to stored location
                fs.Seek(info.Location, SeekOrigin.Begin);

                // Single read to get all the peaks
                if (fs.Read(peaks, 0, peaks.Length) < peaks.Length)
                    throw new IOException(Resources.BiblioSpecLibrary_ReadSpectrum_Failure_trying_to_read_peaks);
            }

            // Build the list
            var arrayMI = new SpectrumPeaksInfo.MI[info.NumPeaks];

            for (int i = 0, iNext = 0; i < peaks.Length; i += lenPair)
            {
                arrayMI[iNext].Intensity = BitConverter.ToSingle(peaks, i + sizeof (Single));
                arrayMI[iNext++].Mz = BitConverter.ToSingle(peaks, i);
            }

            return arrayMI;
        }
Ejemplo n.º 12
0
        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));
        }