private void AddChromatogramsForFilterPair(ChromDataCollectorSet[] chromMaps, SpectrumFilterPair filterPair) { // Fill the chromatograms that were actually extracted foreach (var chromMap in chromMaps) { if (filterPair.Id >= chromMap.PrecursorCollectorMap.Count || chromMap.PrecursorCollectorMap[filterPair.Id] == null) continue; var pairPrecursor = chromMap.PrecursorCollectorMap[filterPair.Id]; chromMap.PrecursorCollectorMap[filterPair.Id] = null; var collector = pairPrecursor.Item2; var scanIdCollector = chromMap.ScanIdsCollector; var timesCollector = chromMap.SharedTimesCollector; if (chromMap.IsGroupedTime) { scanIdCollector = collector.ScansCollector; timesCollector = collector.GroupedTimesCollector; } foreach (var pairProduct in collector.ProductIntensityMap) { var chromCollector = pairProduct.Value; if (timesCollector != null) { chromCollector.SetScans(scanIdCollector); chromCollector.SetTimes(timesCollector); } _collectors.AddCollector(pairProduct.Key.FilterId, chromCollector); } } }
public SpectrumFilter(SrmDocument document, MsDataFileUri msDataFileUri, IFilterInstrumentInfo instrumentInfo, IRetentionTimePredictor retentionTimePredictor = null, bool firstPass = false) { _fullScan = document.Settings.TransitionSettings.FullScan; _instrument = document.Settings.TransitionSettings.Instrument; _acquisitionMethod = _fullScan.AcquisitionMethod; if (instrumentInfo != null) _isWatersFile = instrumentInfo.IsWatersFile; IsFirstPass = firstPass; var comparer = PrecursorTextId.PrecursorTextIdComparerInstance; var dictPrecursorMzToFilter = new SortedDictionary<PrecursorTextId, SpectrumFilterPair>(comparer); if (EnabledMs || EnabledMsMs) { if (EnabledMs) { _isHighAccMsFilter = !Equals(_fullScan.PrecursorMassAnalyzer, FullScanMassAnalyzerType.qit); if (!firstPass) { var key = new PrecursorTextId(0, null, ChromExtractor.summed); // TIC dictPrecursorMzToFilter.Add(key, new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, dictPrecursorMzToFilter.Count, _instrument.MinTime, _instrument.MaxTime, null, null, 0, _isHighAccMsFilter, _isHighAccProductFilter)); key = new PrecursorTextId(0, null, ChromExtractor.base_peak); // BPC dictPrecursorMzToFilter.Add(key, new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, dictPrecursorMzToFilter.Count, _instrument.MinTime, _instrument.MaxTime, null, null, 0, _isHighAccMsFilter, _isHighAccProductFilter)); } } if (EnabledMsMs) { _isHighAccProductFilter = !Equals(_fullScan.ProductMassAnalyzer, FullScanMassAnalyzerType.qit); if (_fullScan.AcquisitionMethod == FullScanAcquisitionMethod.DIA && _fullScan.IsolationScheme.IsAllIons) { if (instrumentInfo != null) { _isWatersMse = _isWatersFile; _isAgilentMse = instrumentInfo.IsAgilentFile; } _mseLevel = 1; } } Func<double, double> calcWindowsQ1 = _fullScan.GetPrecursorFilterWindow; Func<double, double> calcWindowsQ3 = _fullScan.GetProductFilterWindow; _minTime = _instrument.MinTime; _maxTime = _instrument.MaxTime; bool canSchedule = CanSchedule(document, retentionTimePredictor); // TODO: Figure out a way to turn off time sharing on first SIM scan so that // times can be shared for MS1 without SIM scans _isSharedTime = !canSchedule; // If we're using bare measured drift times from spectral libraries, go get those now var libraryIonMobilityInfo = document.Settings.PeptideSettings.Prediction.UseLibraryDriftTimes ? document.Settings.GetIonMobilities(msDataFileUri) : null; foreach (var nodePep in document.Molecules) { if (firstPass && !retentionTimePredictor.IsFirstPassPeptide(nodePep)) continue; foreach (TransitionGroupDocNode nodeGroup in nodePep.Children) { if (nodeGroup.Children.Count == 0) continue; double? minTime = _minTime, maxTime = _maxTime; double? startDriftTimeMsec = null, endDriftTimeMsec = null; double windowDT; double highEnergyDriftTimeOffsetMsec = 0; DriftTimeInfo centerDriftTime = document.Settings.PeptideSettings.Prediction.GetDriftTime( nodePep, nodeGroup, libraryIonMobilityInfo, out windowDT); if (centerDriftTime.DriftTimeMsec(false).HasValue) { startDriftTimeMsec = centerDriftTime.DriftTimeMsec(false) - windowDT / 2; // Get the low energy drift time endDriftTimeMsec = startDriftTimeMsec + windowDT; highEnergyDriftTimeOffsetMsec = centerDriftTime.HighEnergyDriftTimeOffsetMsec; } if (canSchedule) { if (RetentionTimeFilterType.scheduling_windows == _fullScan.RetentionTimeFilterType) { double? centerTime = null; double windowRT = 0; if (retentionTimePredictor != null) { centerTime = retentionTimePredictor.GetPredictedRetentionTime(nodePep); } else { var prediction = document.Settings.PeptideSettings.Prediction; if (prediction.RetentionTime == null || !prediction.RetentionTime.IsAutoCalculated) { centerTime = document.Settings.PeptideSettings.Prediction.PredictRetentionTimeForChromImport( document, nodePep, nodeGroup, out windowRT); } } // Force the center time to be at least zero if (centerTime.HasValue && centerTime.Value < 0) centerTime = 0; if (_fullScan.RetentionTimeFilterLength != 0) { windowRT = _fullScan.RetentionTimeFilterLength * 2; } if (centerTime != null) { double startTime = centerTime.Value - windowRT / 2; double endTime = startTime + windowRT; minTime = Math.Max(minTime ?? 0, startTime); maxTime = Math.Min(maxTime ?? double.MaxValue, endTime); } } else if (RetentionTimeFilterType.ms2_ids == _fullScan.RetentionTimeFilterType) { var times = document.Settings.GetBestRetentionTimes(nodePep, msDataFileUri); if (times.Length > 0) { minTime = Math.Max(minTime ?? 0, times.Min() - _fullScan.RetentionTimeFilterLength); maxTime = Math.Min(maxTime ?? double.MaxValue, times.Max() + _fullScan.RetentionTimeFilterLength); } } } SpectrumFilterPair filter; string textId = nodePep.RawTextId; // Modified Sequence for peptides, or some other string for custom ions double mz = nodeGroup.PrecursorMz; var key = new PrecursorTextId(mz, textId, ChromExtractor.summed); if (!dictPrecursorMzToFilter.TryGetValue(key, out filter)) { filter = new SpectrumFilterPair(key, nodePep.Color, dictPrecursorMzToFilter.Count, minTime, maxTime, startDriftTimeMsec, endDriftTimeMsec, highEnergyDriftTimeOffsetMsec, _isHighAccMsFilter, _isHighAccProductFilter); dictPrecursorMzToFilter.Add(key, filter); } if (!EnabledMs) { filter.AddQ3FilterValues(from TransitionDocNode nodeTran in nodeGroup.Children select nodeTran.Mz, calcWindowsQ3); } else if (!EnabledMsMs) { filter.AddQ1FilterValues(GetMS1MzValues(nodeGroup), calcWindowsQ1); } else { filter.AddQ1FilterValues(GetMS1MzValues(nodeGroup), calcWindowsQ1); filter.AddQ3FilterValues(from TransitionDocNode nodeTran in nodeGroup.Children where !nodeTran.IsMs1 select nodeTran.Mz, calcWindowsQ3); } } } _filterMzValues = dictPrecursorMzToFilter.Values.ToArray(); var listChromKeyFilterIds = new List<ChromKey>(); foreach (var spectrumFilterPair in _filterMzValues) { spectrumFilterPair.AddChromKeys(listChromKeyFilterIds); } _productChromKeys = listChromKeyFilterIds.ToArray(); // Sort a copy of the filter pairs by maximum retention time so that we can detect when // filters are no longer active. _filterRTValues = new SpectrumFilterPair[_filterMzValues.Length]; Array.Copy(_filterMzValues, _filterRTValues, _filterMzValues.Length); Array.Sort(_filterRTValues, CompareByRT); } InitRTLimits(); }
public SpectrumFilterPair[] RemoveFinishedFilterPairs(double retentionTime) { int startIndex = _retentionTimeIndex; if (retentionTime < 0) _retentionTimeIndex = _filterRTValues.Length; else if (!IsTimeOrderedExtraction) { // Wait until the end to release chromatograms, when we can't be sure // that all chromatograms for a peptide have been seen just because a // spectrum with a later time has been seen. _retentionTimeIndex = 0; } else { while (_retentionTimeIndex < _filterRTValues.Length) { var maxTime = _filterRTValues[_retentionTimeIndex].MaxTime; if (!maxTime.HasValue || maxTime > retentionTime) break; _retentionTimeIndex++; } } var donePairs = new SpectrumFilterPair[_retentionTimeIndex - startIndex]; for (int i = 0; i < donePairs.Length; i++) donePairs[i] = _filterRTValues[startIndex++]; return donePairs; }
/// <summary> /// Compare filter pairs by maximum retention time. /// </summary> private int CompareByRT(SpectrumFilterPair x, SpectrumFilterPair y) { return !x.MaxTime.HasValue ? 1 : !y.MaxTime.HasValue ? -1 : x.MaxTime.Value.CompareTo(y.MaxTime.Value); }
public IsotopeDistInfo(MassDistribution massDistribution, double monoisotopicMass, bool isMassH, // Is monoisotopicMass M+H, or just M as in small molecule use? int charge, Func<double, double> calcFilterWindow, double massResolution, double minimumAbundance) { _monoisotopicMass = monoisotopicMass; _charge = charge; _isMassH = isMassH; // Get peak center of mass values for the given resolution var q1FilterValues = MassDistribution.NewInstance(massDistribution, massResolution, 0).Keys.ToList(); // Find the monoisotopic m/z and make sure it is exactly the expected number double monoMz = isMassH ? SequenceMassCalc.GetMZ(_monoisotopicMass, _charge) : BioMassCalc.CalculateIonMz(_monoisotopicMass, _charge); double monoMzDist = monoMz; int monoMassIndex = 0; for (int i = 0; i < q1FilterValues.Count; i++) { double peakCenterMz = q1FilterValues[i]; double filterWindow = calcFilterWindow(peakCenterMz); double startMz = peakCenterMz - filterWindow/2; double endMz = startMz + filterWindow; if (startMz < monoMz && monoMz < endMz) { monoMzDist = q1FilterValues[i]; q1FilterValues[i] = monoMz; monoMassIndex = i; break; } } // Insert a M-1 peak, even if it is not expected in the isotope mass distribution if (monoMassIndex == 0 && q1FilterValues.Count > 1) { // Use the delta from the original distribution monoMz to the next peak q1FilterValues.Insert(0, monoMz + monoMzDist - q1FilterValues[1]); monoMassIndex++; } if (!q1FilterValues.Any()) // As is small molecule docs with mz values only, no formulas return; // Use the filtering algorithm that will be used on real data to determine the // expected proportions of the mass distribution that will end up filtered into // peaks // CONSIDER: Mass accuracy information is not calculated here var key = new PrecursorTextId(q1FilterValues[monoMassIndex], null, ChromExtractor.summed); var filter = new SpectrumFilterPair(key, PeptideDocNode.UNKNOWN_COLOR, 0, null, null, null, null, 0, false, false); filter.AddQ1FilterValues(q1FilterValues, calcFilterWindow); var expectedSpectrum = filter.FilterQ1SpectrumList(new[] { new MsDataSpectrum { Mzs = massDistribution.Keys.ToArray(), Intensities = massDistribution.Values.ToArray() } }); int startIndex = expectedSpectrum.Intensities.IndexOf(inten => inten >= minimumAbundance); if (startIndex == -1) { throw new InvalidOperationException( string.Format(Resources.IsotopeDistInfo_IsotopeDistInfo_Minimum_abundance__0__too_high, minimumAbundance)); } // Always include the M-1 peak, even if it is expected to have zero intensity if (startIndex > monoMassIndex - 1) startIndex = monoMassIndex - 1; if (startIndex < 0) startIndex = 0; int endIndex = expectedSpectrum.Intensities.LastIndexOf(inten => inten >= minimumAbundance) + 1; int countPeaks = endIndex - startIndex; var listProportionIndices = new List<KeyValuePair<float, int>>(countPeaks); for (int i = 0; i < countPeaks; i++) { listProportionIndices.Add(new KeyValuePair<float, int>( expectedSpectrum.Intensities[i + startIndex], i)); } // Sort proportions descending. listProportionIndices.Sort((p1, p2) => Comparer.Default.Compare(p2.Key, p1.Key)); // Set proportions and ranks back in the original locations var expectedProportionRanks = new KeyValuePair<float, int>[countPeaks]; for (int i = 0; i < countPeaks; i++) { expectedProportionRanks[listProportionIndices[i].Value] = new KeyValuePair<float, int>(listProportionIndices[i].Key, i + 1); } // TODO: Can this be discarded? // MassDistribution = massDistribution; MonoMassIndex = monoMassIndex - startIndex; // Find the base peak and fill in the masses and proportions var expectedPeaks = new List<MzRankProportion>(); for (int i = 0; i < countPeaks; i++) { float expectedProportion = expectedProportionRanks[i].Key; int rank = expectedProportionRanks[i].Value; expectedPeaks.Add(new MzRankProportion(q1FilterValues[i + startIndex], rank, expectedProportion)); if (expectedProportion > expectedProportionRanks[BaseMassIndex].Key) BaseMassIndex = i; } ExpectedPeaks = expectedPeaks; }