public static IEnumerable <LCIMSMSFeature> FindDriftTimePeaks(Peak driftProfilePeak, LCIMSMSFeature lcimsmsFeature, double averageTOFLength, double framePressure) { var imsMsFeatureList = lcimsmsFeature.imsMsFeatureList; var sortByScanLCQuery = from imsMsFeature in imsMsFeatureList orderby imsMsFeature.ScanLC select imsMsFeature; var globalIMSScanMinimum = double.MaxValue; var globalIMSScanMaximum = double.MinValue; // Grab all of the intensity values for each IMS-MS Feature and find the global minimum and maximum Drift Times foreach (var imsMsFeature in sortByScanLCQuery) { imsMsFeature.GetMinAndMaxIMSScan(out var localIMSScanMinimum, out var localIMSScanMaximum); if (localIMSScanMinimum < globalIMSScanMinimum) { globalIMSScanMinimum = localIMSScanMinimum; } if (localIMSScanMaximum > globalIMSScanMaximum) { globalIMSScanMaximum = localIMSScanMaximum; } } var smoothedDriftProfilePeak = PeakUtil.KDESmooth(driftProfilePeak, Settings.SmoothingStDev); // TODO: Find a good value. 0.15? Less smooth = more conformations! var smoothedDriftProfileInterpolation = PeakUtil.GetLinearInterpolationMethod(smoothedDriftProfilePeak); var xyPairList = new List <XYPair>(); var peakList = new List <Peak>(); var previousIntensity = double.MinValue; var movingUp = true; // lcimsmsFeature.GetMinAndMaxScanLC(out var minScanLC, out var maxScanLC); var minimumIntensityToConsider = smoothedDriftProfilePeak.GetMaximumYValue() * 0.05; //DisplayPeakXYData(smoothedDriftProfilePeak); //Console.WriteLine("Global IMS Scan Min = " + globalIMSScanMinimum + "\tGlobal IMS Scan Max = " + globalIMSScanMaximum); for (var i = globalIMSScanMinimum; i <= globalIMSScanMaximum; i += 1) { var imsScan = i; var intensity = smoothedDriftProfileInterpolation.Interpolate(imsScan); if (intensity > minimumIntensityToConsider) { //Console.WriteLine(imsScan + "\t" + intensity + "\t" + movingUp); if (intensity > previousIntensity) { // End of Peak if (!movingUp && xyPairList.Count > 0) { PadXYPairsWithZeros(ref xyPairList, 2); //xyPairList = PadXYPairsWithZeros(xyPairList, imsScanMinimum, i - DRIFT_TIME_SLICE_WIDTH, 1); var peak = new Peak(xyPairList); if (peak.XYPairList.Count >= 7) { peakList.Add(peak); } // Start over with a new Peak xyPairList.Clear(); movingUp = true; } } else { movingUp = false; } var xyPair = new XYPair(imsScan, intensity); xyPairList.Add(xyPair); previousIntensity = intensity; } else { movingUp = false; previousIntensity = 0; } } // When you get to the end, end the last Peak, but only if it has a non-zero value if (xyPairList.Any(xyPair => xyPair.YValue > minimumIntensityToConsider)) { PadXYPairsWithZeros(ref xyPairList, 2); //xyPairList = PadXYPairsWithZeros(xyPairList, imsScanMinimum, globalIMSScanMaximum, 1); var lastPeak = new Peak(xyPairList); if (lastPeak.XYPairList.Count >= 7) { peakList.Add(lastPeak); } } // var resolvingPower = GetResolvingPower(lcimsmsFeature.Charge); var newLcImsMsFeatureList = new List <LCIMSMSFeature>(); foreach (var peak in peakList) { var repIMSScan = peak.GetQuadraticFit(); // TODO: Fix this //double theoreticalFWHM = driftTime / resolvingPower; double theoreticalFWHM = 3; peak.GetMinAndMaxXValues(out var minimumXValue, out var maximumXValue); const int numPoints = 100; var normalDistributionXYPairList = PeakUtil.CreateTheoreticalGaussianPeak(repIMSScan, theoreticalFWHM, numPoints); PadXYPairsWithZeros(ref normalDistributionXYPairList, 5); var normalDistributionPeak = new Peak(normalDistributionXYPairList); var peakInterpolation = PeakUtil.GetLinearInterpolationMethod(peak); var fitScore = PeakUtil.CalculatePeakFit(peak, normalDistributionPeak, 0); // Create a new LC-IMS-MS Feature var newLcImsMsFeature = new LCIMSMSFeature(lcimsmsFeature.Charge) { OriginalIndex = lcimsmsFeature.OriginalIndex, IMSScore = (float)fitScore, AbundanceMaxRaw = Math.Round(peak.GetMaximumYValue()), // Using Math.Floor instead of Math.Round because I used to cast this to an int which is essentially Math.Floor. // The difference is negligible, but OHSU would complain if results were the slightest bit different if the app was re-run on the same dataset. AbundanceSumRaw = Math.Floor(peakInterpolation.Integrate(peak.GetMaximumXValue())), DriftTime = ConvertIMSScanToDriftTime(repIMSScan, averageTOFLength, framePressure) }; // Create new IMS-MS Features by grabbing MS Features in each LC Scan that are in the defined window of the detected drift time foreach (var imsMsFeature in lcimsmsFeature.imsMsFeatureList) { var msFeatures = imsMsFeature.FindMSFeaturesInScanIMSRange(minimumXValue, maximumXValue).ToList(); if (!msFeatures.Any()) { continue; } var newImsMsFeature = new imsMsFeature(imsMsFeature.ScanLC, imsMsFeature.Charge); newImsMsFeature.AddMSFeatureList(msFeatures); newLcImsMsFeature.AddImsMsFeature(newImsMsFeature); } if (newLcImsMsFeature.imsMsFeatureList.Count > 0) { newLcImsMsFeatureList.Add(newLcImsMsFeature); /* * // TODO: Find LC Peaks * var sortByScanLC = from imsMsFeature in newLCIMSMSFeature.imsMsFeatureList * orderby imsMsFeature.ScanLC ascending * select imsMsFeature; * * Console.WriteLine("*************************************************"); * Console.WriteLine("Index = " + index + "\tMass = " + newLCIMSMSFeature.CalculateAverageMass() + "\tDrift = " + driftTime + "\tLC Range = " + sortByScanLC.First().ScanLC + "\t" + sortByScanLC.Last().ScanLC); * * List<XYPair> lcXYPairList = new List<XYPair>(); * int scanLC = sortByScanLC.First().ScanLC - 1; * * foreach (imsMsFeature imsMsFeature in sortByScanLC) * { * int currentScanLC = imsMsFeature.ScanLC; * * for (int i = scanLC + 1; i < currentScanLC; i++) * { * XYPair zeroValue = new XYPair(i, 0); * lcXYPairList.Add(zeroValue); * Console.Write("0\t"); * } * * XYPair xyPair = new XYPair(currentScanLC, imsMsFeature.GetIntensity()); * lcXYPairList.Add(xyPair); * * scanLC = currentScanLC; * * Console.Write(imsMsFeature.GetIntensity() + "\t"); * } * Console.WriteLine(string.Empty); * Console.WriteLine("*************************************************"); */ // TODO: Calculate LC Score } else { //Console.WriteLine("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ FOUND EMPTY $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"); // TODO: Figure out why this actually happens. I believe that this SHOULD NOT happen. Below is a hack to return a conformation even if this happens // It actually looks like most of these occurrences are due to large gaps in the drift time, which cause a small peak to be found in the gap which has no members. //Console.WriteLine("**********************************************************************"); //Console.WriteLine("Detected Drift Time = " + driftTime + "\tLow = " + lowDriftTime + "\tHigh = " + highDriftTime); //lcimsmsFeature.PrintLCAndDriftTimeMap(); //Console.WriteLine("**********************************************************************"); //Console.WriteLine("==============================================================="); //Console.WriteLine("DT = " + driftTime + "\tLow DT = " + lowDriftTime + "\tHigh DT = " + highDriftTime); //Console.WriteLine("Global Min = " + globalDriftTimeMinimum + "\tGlobal Max = " + globalDriftTimeMaximum); //peak.PrintPeakToConsole(); //Console.WriteLine("==============================================================="); } } // Find the Conformation that has the highest member count and store the value into all conformations of this LC-IMS-MS Feature if (newLcImsMsFeatureList.Count > 0) { var maxMemberCount = newLcImsMsFeatureList.Select(feature => feature.GetMemberCount()).Max(); foreach (var feature in newLcImsMsFeatureList) { feature.MaxMemberCount = maxMemberCount; } } return(newLcImsMsFeatureList); }
public static void MergeImsMsFeatures(imsMsFeature dominantFeature, imsMsFeature recessiveFeature) { dominantFeature.AddMSFeatureList(recessiveFeature.MSFeatureList); recessiveFeature.MSFeatureList.Clear(); recessiveFeature.ScanLC = int.MinValue; }