/// <summary> /// Add the parent ion, or associate the fragmentation scan with an existing parent ion /// </summary> /// <param name="scanList"></param> /// <param name="surveyScanIndex"></param> /// <param name="parentIonMZ"></param> /// <param name="fragScanIndex"></param> /// <param name="spectraCache"></param> /// <param name="sicOptions"></param> public void AddUpdateParentIons( clsScanList scanList, int surveyScanIndex, double parentIonMZ, int fragScanIndex, clsSpectraCache spectraCache, clsSICOptions sicOptions) { AddUpdateParentIons(scanList, surveyScanIndex, parentIonMZ, 0, 0, fragScanIndex, spectraCache, sicOptions); }
/// <summary> /// Check whether the scan number is within the range specified by sicOptions /// </summary> /// <param name="scanNumber"></param> /// <param name="sicOptions"></param> /// <returns>True if filtering is disabled, or if scanNumber is within the limits</returns> public bool CheckScanInRange( int scanNumber, clsSICOptions sicOptions) { if (sicOptions.ScanRangeStart >= 0 && sicOptions.ScanRangeEnd > sicOptions.ScanRangeStart) { if (scanNumber < sicOptions.ScanRangeStart || scanNumber > sicOptions.ScanRangeEnd) { return(false); } } return(true); }
/// <summary> /// Add the parent ion, or associate the fragmentation scan with an existing parent ion /// </summary> /// <param name="scanList"></param> /// <param name="surveyScanIndex"></param> /// <param name="parentIonMZ"></param> /// <param name="mrmInfo"></param> /// <param name="spectraCache"></param> /// <param name="sicOptions"></param> public void AddUpdateParentIons( clsScanList scanList, int surveyScanIndex, double parentIonMZ, clsMRMScanInfo mrmInfo, clsSpectraCache spectraCache, clsSICOptions sicOptions) { for (var mrmIndex = 0; mrmIndex < mrmInfo.MRMMassCount; mrmIndex++) { var mrmDaughterMZ = mrmInfo.MRMMassList[mrmIndex].CentralMass; var mrmToleranceHalfWidth = Math.Round((mrmInfo.MRMMassList[mrmIndex].EndMass - mrmInfo.MRMMassList[mrmIndex].StartMass) / 2, 6); if (mrmToleranceHalfWidth < 0.001) { mrmToleranceHalfWidth = 0.001; } AddUpdateParentIons(scanList, surveyScanIndex, parentIonMZ, mrmDaughterMZ, mrmToleranceHalfWidth, scanList.FragScans.Count - 1, spectraCache, sicOptions); } }
/// <summary> /// Check whether the scan number and elution time are within the ranges specified by sicOptions /// </summary> /// <param name="scanNumber"></param> /// <param name="elutionTime"></param> /// <param name="sicOptions"></param> /// <returns>True if filtering is disabled, or if scanNumber and elutionTime are within the limits</returns> public bool CheckScanInRange( int scanNumber, double elutionTime, clsSICOptions sicOptions) { if (!CheckScanInRange(scanNumber, sicOptions)) { return(false); } if (sicOptions.RTRangeStart >= 0 && sicOptions.RTRangeEnd > sicOptions.RTRangeStart) { if (elutionTime < sicOptions.RTRangeStart || elutionTime > sicOptions.RTRangeEnd) { return(false); } } return(true); }
/// <summary> /// Looks for the reporter ion m/z values, +/- a tolerance /// Calls AggregateIonsInRange with returnMax = True, meaning we're reporting the maximum ion abundance for each reporter ion m/z /// </summary> /// <param name="rawFileReader"></param> /// <param name="dataAggregation"></param> /// <param name="includeFtmsColumns"></param> /// <param name="sicOptions"></param> /// <param name="scanList"></param> /// <param name="spectraCache"></param> /// <param name="currentScan"></param> /// <param name="writer"></param> /// <param name="reporterIons"></param> /// <param name="delimiter"></param> /// <param name="saveUncorrectedIntensities"></param> /// <param name="saveObservedMasses"></param> /// <remarks></remarks> private void FindReporterIonsWork( XRawFileIO rawFileReader, clsDataAggregation dataAggregation, bool includeFtmsColumns, clsSICOptions sicOptions, clsScanList scanList, clsSpectraCache spectraCache, clsScanInfo currentScan, TextWriter writer, IList <clsReporterIonInfo> reporterIons, char delimiter, bool saveUncorrectedIntensities, bool saveObservedMasses) { const bool USE_MAX_ABUNDANCE_IN_WINDOW = true; // The following will be a value between 0 and 100 // Using Absolute Value of percent change to avoid averaging both negative and positive values double parentIonMZ; if (currentScan.FragScanInfo.ParentIonInfoIndex >= 0 && currentScan.FragScanInfo.ParentIonInfoIndex < scanList.ParentIons.Count) { parentIonMZ = scanList.ParentIons[currentScan.FragScanInfo.ParentIonInfoIndex].MZ; } else { parentIonMZ = 0; } if (!spectraCache.GetSpectrum(currentScan.ScanNumber, out var spectrum, true)) { SetLocalErrorCode(clsMASIC.eMasicErrorCodes.ErrorUncachingSpectrum); return; } // Initialize the arrays used to track the observed reporter ion values var reporterIntensities = new double[reporterIons.Count]; var reporterIntensitiesCorrected = new double[reporterIons.Count]; var closestMZ = new double[reporterIons.Count]; // Initialize the output variables var dataColumns = new List <string>() { sicOptions.DatasetID.ToString(), currentScan.ScanNumber.ToString(), currentScan.FragScanInfo.CollisionMode, StringUtilities.DblToString(parentIonMZ, 2), StringUtilities.DblToString(currentScan.BasePeakIonIntensity, 2), StringUtilities.DblToString(currentScan.BasePeakIonMZ, 4) }; var reporterIntensityList = new List <string>(reporterIons.Count); var obsMZList = new List <string>(reporterIons.Count); var uncorrectedIntensityList = new List <string>(reporterIons.Count); var ftmsSignalToNoise = new List <string>(reporterIons.Count); var ftmsResolution = new List <string>(reporterIons.Count); //var ftmsLabelDataMz = new List<string>(reporterIons.Count); double reporterIntensityMax = 0; // Find the reporter ion intensities // Also keep track of the closest m/z for each reporter ion // Note that we're using the maximum intensity in the range (not the sum) for (var reporterIonIndex = 0; reporterIonIndex < reporterIons.Count; reporterIonIndex++) { var ion = reporterIons[reporterIonIndex]; // Search for the reporter ion MZ in this mass spectrum reporterIntensities[reporterIonIndex] = dataAggregation.AggregateIonsInRange( spectrum, ion.MZ, ion.MZToleranceDa, out _, out closestMZ[reporterIonIndex], USE_MAX_ABUNDANCE_IN_WINDOW); ion.SignalToNoise = 0; ion.Resolution = 0; ion.LabelDataMZ = 0; } if (includeFtmsColumns && currentScan.IsFTMS) { // Retrieve the label data for this spectrum rawFileReader.GetScanLabelData(currentScan.ScanNumber, out var ftLabelData); // Find each reporter ion in ftLabelData for (var reporterIonIndex = 0; reporterIonIndex < reporterIons.Count; reporterIonIndex++) { var mzToFind = reporterIons[reporterIonIndex].MZ; var mzToleranceDa = reporterIons[reporterIonIndex].MZToleranceDa; var highestIntensity = 0.0; var udtBestMatch = new udtFTLabelInfoType(); var matchFound = false; foreach (var labelItem in ftLabelData) { // Compare labelItem.Mass (which is m/z of the ion in labelItem) to the m/z of the current reporter ion if (Math.Abs(mzToFind - labelItem.Mass) > mzToleranceDa) { continue; } // m/z is within range if (labelItem.Intensity > highestIntensity) { udtBestMatch = labelItem; highestIntensity = labelItem.Intensity; matchFound = true; } } if (matchFound) { reporterIons[reporterIonIndex].SignalToNoise = udtBestMatch.SignalToNoise; reporterIons[reporterIonIndex].Resolution = udtBestMatch.Resolution; reporterIons[reporterIonIndex].LabelDataMZ = udtBestMatch.Mass; } } } // Populate reporterIntensitiesCorrected with the data in reporterIntensities Array.Copy(reporterIntensities, reporterIntensitiesCorrected, reporterIntensities.Length); if (mOptions.ReporterIons.ReporterIonApplyAbundanceCorrection) { if (mOptions.ReporterIons.ReporterIonMassMode == clsReporterIons.eReporterIonMassModeConstants.ITraqFourMZ || mOptions.ReporterIons.ReporterIonMassMode == clsReporterIons.eReporterIonMassModeConstants.ITraqEightMZHighRes || mOptions.ReporterIons.ReporterIonMassMode == clsReporterIons.eReporterIonMassModeConstants.ITraqEightMZLowRes || mOptions.ReporterIons.ReporterIonMassMode == clsReporterIons.eReporterIonMassModeConstants.TMTTenMZ || mOptions.ReporterIons.ReporterIonMassMode == clsReporterIons.eReporterIonMassModeConstants.TMTElevenMZ || mOptions.ReporterIons.ReporterIonMassMode == clsReporterIons.eReporterIonMassModeConstants.TMTSixteenMZ) { // Correct the reporter ion intensities using the Reporter Ion Intensity Corrector class if (intensityCorrector.ReporterIonMode != mOptions.ReporterIons.ReporterIonMassMode || intensityCorrector.ITraq4PlexCorrectionFactorType != mOptions.ReporterIons.ReporterIonITraq4PlexCorrectionFactorType) { intensityCorrector.UpdateReporterIonMode( mOptions.ReporterIons.ReporterIonMassMode, mOptions.ReporterIons.ReporterIonITraq4PlexCorrectionFactorType); } // Count the number of non-zero data points in reporterIntensitiesCorrected() var positiveCount = 0; for (var reporterIonIndex = 0; reporterIonIndex < reporterIons.Count; reporterIonIndex++) { if (reporterIntensitiesCorrected[reporterIonIndex] > 0) { positiveCount += 1; } } // Apply the correction if 2 or more points are non-zero if (positiveCount >= 2) { intensityCorrector.ApplyCorrection(reporterIntensitiesCorrected); } } } // Now construct the string of intensity values, delimited by delimiter // Will also compute the percent change in intensities // Initialize the variables used to compute the weighted average percent change double pctChangeSum = 0; double originalIntensitySum = 0; for (var reporterIonIndex = 0; reporterIonIndex < reporterIons.Count; reporterIonIndex++) { if (!reporterIons[reporterIonIndex].ContaminantIon) { // Update the PctChange variables and the IntensityMax variable only if this is not a Contaminant Ion originalIntensitySum += reporterIntensities[reporterIonIndex]; if (reporterIntensities[reporterIonIndex] > 0) { // Compute the percent change, then update pctChangeSum var pctChange = (reporterIntensitiesCorrected[reporterIonIndex] - reporterIntensities[reporterIonIndex]) / reporterIntensities[reporterIonIndex]; // Using Absolute Value here to prevent negative changes from cancelling out positive changes pctChangeSum += Math.Abs(pctChange * reporterIntensities[reporterIonIndex]); } if (reporterIntensitiesCorrected[reporterIonIndex] > reporterIntensityMax) { reporterIntensityMax = reporterIntensitiesCorrected[reporterIonIndex]; } } if (!reporterIons[reporterIonIndex].ContaminantIon || saveUncorrectedIntensities) { // Append the reporter ion intensity to reporterIntensityList // We skip contaminant ions, unless saveUncorrectedIntensities is True, then we include them reporterIntensityList.Add(StringUtilities.DblToString(reporterIntensitiesCorrected[reporterIonIndex], 2)); if (saveObservedMasses) { // Append the observed reporter mass value to obsMZList obsMZList.Add(StringUtilities.DblToString(closestMZ[reporterIonIndex], 3)); } if (saveUncorrectedIntensities) { // Append the original, uncorrected intensity value uncorrectedIntensityList.Add(StringUtilities.DblToString(reporterIntensities[reporterIonIndex], 2)); } if (includeFtmsColumns) { if (Math.Abs(reporterIons[reporterIonIndex].SignalToNoise) < float.Epsilon && Math.Abs(reporterIons[reporterIonIndex].Resolution) < float.Epsilon && Math.Abs(reporterIons[reporterIonIndex].LabelDataMZ) < float.Epsilon) { // A match was not found in the label data; display blanks (not zeroes) ftmsSignalToNoise.Add(string.Empty); ftmsResolution.Add(string.Empty); //ftmsLabelDataMz.Add(string.Empty); } else { ftmsSignalToNoise.Add(StringUtilities.DblToString(reporterIons[reporterIonIndex].SignalToNoise, 2)); ftmsResolution.Add(StringUtilities.DblToString(reporterIons[reporterIonIndex].Resolution, 2)); //ftmsLabelDataMz.Add(StringUtilities.DblToString(reporterIons(reporterIonIndex).LabelDataMZ, 4)); } } } } // Compute the weighted average percent intensity correction value float weightedAvgPctIntensityCorrection; if (originalIntensitySum > 0) { weightedAvgPctIntensityCorrection = (float)(pctChangeSum / originalIntensitySum * 100); } else { weightedAvgPctIntensityCorrection = 0; } // Resize the target list capacity to large enough to hold all data. dataColumns.Capacity = reporterIntensityList.Count + 3 + obsMZList.Count + uncorrectedIntensityList.Count + ftmsSignalToNoise.Count + ftmsResolution.Count; // Append the maximum reporter ion intensity then the individual reporter ion intensities dataColumns.Add(StringUtilities.DblToString(reporterIntensityMax, 2)); dataColumns.AddRange(reporterIntensityList); // Append the weighted average percent intensity correction if (weightedAvgPctIntensityCorrection < float.Epsilon) { dataColumns.Add("0"); } else { dataColumns.Add(StringUtilities.DblToString(weightedAvgPctIntensityCorrection, 1)); } if (saveObservedMasses) { dataColumns.AddRange(obsMZList); } if (saveUncorrectedIntensities) { dataColumns.AddRange(uncorrectedIntensityList); } if (includeFtmsColumns) { dataColumns.AddRange(ftmsSignalToNoise); dataColumns.AddRange(ftmsResolution); // Uncomment to include the label data m/z value in the _ReporterIons.txt file //if (saveObservedMasses) // dataColumns.AddRange(ftmsLabelDataMz) } writer.WriteLine(string.Join(delimiter.ToString(), dataColumns)); }
/// <summary> /// Add the parent ion, or associate the fragmentation scan with an existing parent ion /// /// Checks to see if the parent ion specified by surveyScanIndex and parentIonMZ exists in .ParentIons() /// If mrmDaughterMZ is > 0, also considers that value when determining uniqueness /// /// If the parent ion entry already exists, adds an entry to .FragScanIndices() /// If it does not exist, adds a new entry to .ParentIons() /// </summary> /// <param name="scanList"></param> /// <param name="surveyScanIndex"> /// If this is less than 0 the first MS2 scan(s) in the file occurred before we encountered a survey scan /// In this case, we cannot properly associate the fragmentation scan with a survey scan /// </param> /// <param name="parentIonMZ"></param> /// <param name="mrmDaughterMZ"></param> /// <param name="mrmToleranceHalfWidth"></param> /// <param name="fragScanIndex">This is typically equal to scanList.FragScans.Count - 1</param> /// <param name="spectraCache"></param> /// <param name="sicOptions"></param> private void AddUpdateParentIons( clsScanList scanList, int surveyScanIndex, double parentIonMZ, double mrmDaughterMZ, double mrmToleranceHalfWidth, int fragScanIndex, clsSpectraCache spectraCache, clsSICOptions sicOptions) { const double MINIMUM_TOLERANCE_PPM = 0.01; const double MINIMUM_TOLERANCE_DA = 0.0001; var parentIonIndex = 0; double parentIonTolerance; if (sicOptions.SICToleranceIsPPM) { parentIonTolerance = sicOptions.SICTolerance / sicOptions.CompressToleranceDivisorForPPM; if (parentIonTolerance < MINIMUM_TOLERANCE_PPM) { parentIonTolerance = MINIMUM_TOLERANCE_PPM; } } else { parentIonTolerance = sicOptions.SICTolerance / sicOptions.CompressToleranceDivisorForDa; if (parentIonTolerance < MINIMUM_TOLERANCE_DA) { parentIonTolerance = MINIMUM_TOLERANCE_DA; } } // See if an entry exists yet in .ParentIons for the parent ion for this fragmentation scan var matchFound = false; if (mrmDaughterMZ > 0) { if (sicOptions.SICToleranceIsPPM) { // Force the tolerances to 0.01 m/z units parentIonTolerance = MINIMUM_TOLERANCE_PPM; } else { // Force the tolerances to 0.01 m/z units parentIonTolerance = MINIMUM_TOLERANCE_DA; } } if (parentIonMZ > 0) { var parentIonToleranceDa = GetParentIonToleranceDa(sicOptions, parentIonMZ, parentIonTolerance); for (parentIonIndex = scanList.ParentIons.Count - 1; parentIonIndex >= 0; parentIonIndex += -1) { if (scanList.ParentIons[parentIonIndex].SurveyScanIndex >= surveyScanIndex) { if (Math.Abs(scanList.ParentIons[parentIonIndex].MZ - parentIonMZ) <= parentIonToleranceDa) { if (mrmDaughterMZ < double.Epsilon || Math.Abs(scanList.ParentIons[parentIonIndex].MRMDaughterMZ - mrmDaughterMZ) <= parentIonToleranceDa) { matchFound = true; break; } } } else { break; } } } if (!matchFound) { // Add a new parent ion entry to .ParentIons(), but only if surveyScanIndex is non-negative if (surveyScanIndex < 0) { return; } var newParentIon = new clsParentIonInfo(parentIonMZ) { SurveyScanIndex = surveyScanIndex, CustomSICPeak = false, MRMDaughterMZ = mrmDaughterMZ, MRMToleranceHalfWidth = mrmToleranceHalfWidth }; newParentIon.FragScanIndices.Add(fragScanIndex); newParentIon.OptimalPeakApexScanNumber = scanList.SurveyScans[surveyScanIndex].ScanNumber; // Was: .FragScans(fragScanIndex).ScanNumber newParentIon.PeakApexOverrideParentIonIndex = -1; scanList.FragScans[fragScanIndex].FragScanInfo.ParentIonInfoIndex = scanList.ParentIons.Count; // Look for .MZ in the survey scan, using a tolerance of parentIonTolerance // If found, then update the mass to the matched ion // This is done to determine the parent ion mass more precisely if (sicOptions.RefineReportedParentIonMZ) { if (FindClosestMZ(spectraCache, scanList.SurveyScans, surveyScanIndex, parentIonMZ, parentIonTolerance, out var parentIonMZMatch)) { newParentIon.UpdateMz(parentIonMZMatch); } } scanList.ParentIons.Add(newParentIon); return; } // Add a new entry to .FragScanIndices() for the matching parent ion // However, do not add a new entry if this is an MRM scan if (mrmDaughterMZ < double.Epsilon) { scanList.ParentIons[parentIonIndex].FragScanIndices.Add(fragScanIndex); scanList.FragScans[fragScanIndex].FragScanInfo.ParentIonInfoIndex = parentIonIndex; } }