// Grouping the scans in the file /// <summary> /// Given a file, reads through the scans and groups them into SetOfScans objects, each containing one or more full ms1 scans and the corresponding boxcar scans. /// Discards all ms2 scans (although the SetOfScans object also has a list to hold these, if you wanted to include them). /// This method includes many comments which can be uncommented for debugging to write information to the console. /// </summary> /// <param name="file"></param> /// <returns></returns> list of SetOfScans objects, each SetOfScans contains one full ms1 scan and its corresponding boxcar scans. public static List <SetOfScans> SeparateScans(MsDataFile file) { List <SetOfScans> sorted = new List <SetOfScans>(); // Get only the ms1 and boxcar scans (discard ms2): var ms1scans = file.GetMS1Scans().ToList(); //Console.WriteLine("Number of ms1scans (full ms and boxcar method): " + ms1scans.Count); // Initialize variables: MsDataScan current = ms1scans.ElementAt(0); string currentFilter = current.ScanFilter; //Console.WriteLine("first scan filter: " + currentFilter); MsDataScan next = ms1scans.ElementAt(1); string nextFilter = next.ScanFilter; //Console.WriteLine("next scan filter: " + nextFilter); SetOfScans set = new SetOfScans(); // Loop through to group the scans. This should create as many SetOfScans objects as there are boxes (specified in the setup of the scan). for (int i = 0; i < ms1scans.Count; i++) { if (current.ScanFilter.Contains("Full ms ")) // the space is important! Otherwise this will be recorded as a boxcar scan instead of an ms1 { set.AddToMs1Scans(current); // Console.WriteLine("Found full ms, added to set"); } // if this boxcar scan has boxcar scans after it else if (current.ScanFilter.Contains("Full msx ms") && next.ScanFilter.Contains("Full msx ms")) { set.AddToBoxcarScans(current); //Console.WriteLine("Found msx ms, added to set"); } // if this boxcar scan is the last boxcar scan in the set, start a new set else if (current.ScanFilter.Contains("Full msx ms") && !next.ScanFilter.Contains("Full msx ms")) { set.AddToBoxcarScans(current); //Console.WriteLine("Found last msx ms in set, added to set"); sorted.Add(set); //Console.WriteLine("Added set to Sorted"); set = new SetOfScans(); } current = next; currentFilter = current.ScanFilter; if ((i + 1) < ms1scans.Count) // if there is a next MsDataScan in the file { next = ms1scans.ElementAt(i + 1); nextFilter = next.ScanFilter; } } return(sorted); }
/// <summary> /// Helper method for CombineScans /// Identifies which scan in the set has the most points in the boxcar range /// </summary> /// <param name="set"></param> /// <param name="boxcar"></param> BestScan object with first index, last index, total intensity, and scan public static BestScan FindBoxcarScan(SetOfScans set, BoxcarRange range, int count) { double bestIntensity = 0; MsDataScan bestScan = set.BoxcarScans[0]; int bestFirstIndex = 0; int bestLastIndex = 0; int bestLen = 0; List <MsDataScan> boxcarScans = set.BoxcarScans; // Check each scan to find the one that corresponds best to the boxcar scan range foreach (var scan in boxcarScans) { BestScan bestrange = FindScanRange(scan, range); // the scan is better than the previous scan if: // it has more m/z values in the range, and if // the total intensity is higher int firstIndex = bestrange.FirstIndex; int lastIndex = bestrange.LastIndex; int currentLen = lastIndex - firstIndex; if (currentLen > bestLen) { if (bestrange.TotalIntensity < bestIntensity) { Console.WriteLine("ACK! scan#: " + count + " has a lot of very low intensity scans and may have been incorrectly counted in a boxcar range!"); } // if the scan has more m/z points in the boxcar range than the previously best scan, update variables. bestLen = currentLen; bestLastIndex = lastIndex; bestFirstIndex = firstIndex; bestScan = scan; } } return(new BestScan(bestFirstIndex, bestLastIndex, bestIntensity, bestScan)); }
/// <summary> /// Helper method for MergeScans /// Combines the 3 scans in a set into one MsDataScan. /// </summary> /// <param name="set"></param> /// <param name="boxcarRanges"></param> /// <returns></returns> MsDataScan combined scans public static MsDataScan CombineScans(SetOfScans set, SetOfBoxcarRanges[] boxcarTypes) { List <double[]> bestPoints = new List <double[]>(); var count = 1; foreach (var boxcarRanges in boxcarTypes) { foreach (var boxcarRange in boxcarRanges) { BestScan bestScan = FindBoxcarScan(set, boxcarRange, count); // find the m/z values and intensities in that scan's x and y arrays between the first and last index, add to the lists for (int i = bestScan.FirstIndex; i <= bestScan.LastIndex; i++) { double x = bestScan.Scan.MassSpectrum.XArray[i]; double y = bestScan.Scan.MassSpectrum.YArray[i]; bestPoints.Add(new double[] { x, y }); } } } // recast bestPoints (List<Double[]>) into double[,] double[,] mzIntensities = new double[bestPoints[0].Length, bestPoints.Count]; for (int i = 0; i < bestPoints[0].Length; i++) { for (int j = 0; j < bestPoints.Count; j++) { mzIntensities[i, j] = bestPoints[j][i]; } } // create and return the new MsDataScan MzSpectrum newMassSpectrum = new MzSpectrum(mzIntensities); MsDataScan newScan = new MsDataScan(newMassSpectrum, count, 1, true, set.BoxcarScans[0].Polarity, set.BoxcarScans[0].RetentionTime, set.BoxcarScans[0].ScanWindowRange, set.BoxcarScans[0].ScanFilter, set.BoxcarScans[0].MzAnalyzer, set.BoxcarScans[0].TotalIonCurrent, set.BoxcarScans[0].InjectionTime, set.BoxcarScans[0].NoiseData, set.BoxcarScans[0].NativeId); count++; return(newScan); }