/// <summary> /// Builds and assigns the spectral trees for each detected chromatogram peak /// </summary> /// <remarks> /// For each detected peak, spectral trees are generated from the MS1 scans including all matching data dependent scans eluting in that retention time range. /// Matching means that the precursor mass of the MS2 scan must match the mass used to create the chromatogram trace within the given mass tolerance. Finally all /// spectral tree with matching data dependent scans are assigned to the detected peak. /// </remarks> private void BuildSpectralTrees(IEnumerable <SpectrumDescriptor> spectrumDescriptors, IEnumerable <DetectedPeakDetails> peakDetails) { SendAndLogTemporaryMessage("Building spectral trees..."); var timer = Stopwatch.StartNew(); DetectedPeakDetailsHelper.AssignSpectrumTreesToPeakDetails(spectrumDescriptors.OfType <ISpectrumDescriptor>(), peakDetails); timer.Stop(); SendAndLogMessage("Building spectral trees takes {0:F2} s.", timer.Elapsed.TotalSeconds); }
/// <summary> /// Assigns to each detected chromatogram peak the nearest MS1 spectrum and all related data dependent spectra and persists the spectra afterwards. /// </summary> /// <param name="spectrumDescriptors">The spectrum descriptors group by file identifier.</param> /// <param name="compoundIon2IsotopePeaksDictionary">The detected peaks for each compound ion as dictionary.</param> private void AssignAndPersistMassSpectra(IEnumerable <SpectrumDescriptor> spectrumDescriptors, IEnumerable <KeyValuePair <UnknownFeatureIonInstanceItem, List <ChromatogramPeakItem> > > compoundIon2IsotopePeaksDictionary) { var time = Stopwatch.StartNew(); SendAndLogTemporaryMessage("Assigning MS1 spectra..."); var defaultCharge = 1; if (spectrumDescriptors.First().ScanEvent.Polarity == PolarityType.Negative) { defaultCharge = -1; } var orderedSpectrumDescriptors = spectrumDescriptors .OrderBy(o => o.Header.RetentionTimeCenter) .ToList(); if (orderedSpectrumDescriptors.Any(a => a.ScanEvent.MSOrder == MSOrderType.MS1) == false) { SendAndLogErrorMessage("Exception, MS1 spectra not available (check spectrum selector node)."); return; } // Create peak details for each detected peak using the charge of the related compound ion var detectedPeakDetails = compoundIon2IsotopePeaksDictionary.SelectMany( sm => sm.Value.Select( s => new DetectedPeakDetails(s) { Charge = sm.Key.Charge == 0 ? defaultCharge : sm.Key.Charge })) .ToList(); DetectedPeakDetailsHelper.AssignMassSpectraToPeakApexes(orderedSpectrumDescriptors, detectedPeakDetails); SendAndLogMessage("Assigning MS1 spectra to chromatogram peak apexes finished after {0}", StringHelper.GetDisplayString(time.Elapsed)); time.Restart(); BuildSpectralTrees(orderedSpectrumDescriptors, detectedPeakDetails); SendAndLogTemporaryMessage("Persisting assigned spectra..."); // get spectrum ids of distinct spectra var distinctSpectrumIds = detectedPeakDetails.SelectMany(s => s.AssignedSpectrumDescriptors) .Select(s => s.Header.SpectrumID) .Distinct() .ToList(); // Divide spectrum ids into parts to reduce the memory foot print. Therefore it is necessary to interrupt the spectra reading, // because otherwise a database locked exception will be thrown when storing the spectra foreach (var spectrumIdsPartition in distinctSpectrumIds .Partition(ServerConfiguration.ProcessingPacketSize)) { // Retrieve mass spectra and create MassSpectrumItem's var distinctSpectra = ProcessingServices.SpectrumProcessingService.ReadSpectraFromCache(spectrumIdsPartition.ToList()) .Select( s => new MassSpectrumItem { ID = s.Header.SpectrumID, FileID = s.Header.FileID, Spectrum = s }) .ToList(); // Persist mass spectra PersistMassSpectra(distinctSpectra); } // Persists peak <-> mass spectrum connections var peaksToMassSpectrumConnectionList = new List <EntityConnectionItemList <ChromatogramPeakItem, MassSpectrumItem> >(detectedPeakDetails.Count); // Get connections between spectrum and chromatographic peak foreach (var item in detectedPeakDetails .Where(w => w.AssignedSpectrumDescriptors.Any())) { var connection = new EntityConnectionItemList <ChromatogramPeakItem, MassSpectrumItem>(item.Peak); peaksToMassSpectrumConnectionList.Add(connection); foreach (var spectrumDescriptor in item.AssignedSpectrumDescriptors) { connection.AddConnection(new MassSpectrumItem { ID = spectrumDescriptor.Header.SpectrumID, FileID = spectrumDescriptor.Header.FileID, // Omit mass spectrum here to reduce the memory footprint (only the IDs are required to persist the connections) }); } } // Persists peak <-> mass spectrum connections EntityDataService.ConnectItems(peaksToMassSpectrumConnectionList); SendAndLogMessage("Persisting spectra finished after {0}", StringHelper.GetDisplayString(time.Elapsed)); m_currentStep += 1; ReportTotalProgress((double)m_currentStep / m_numSteps); time.Stop(); }