public RTMetrics DivideByRT(MzmlParser.Run run, int division, double rtDuration) { double rtSegment = rtDuration / division; rtSegs = new double[division]; List <string> segmentBoundaries = new List <string>(); for (int i = 0; i < division; i++) { rtSegs[i] = run.StartTime + rtSegment * i; if (i > 0) { segmentBoundaries.Add(rtSegs[i - 1] + "_" + rtSegs[i]);//segmentBoundaries is a string denoting the startOfTheRTsegment_endOfTheRTsegment for reference } else { segmentBoundaries.Add(run.StartTime + "_" + rtSegs[i]); } } //dividing basepeaks into segments foreach (MzmlParser.BasePeak basepeak in run.BasePeaks) { //Check to see in which RTsegment this basepeak is: foreach (double rt in basepeak.BpkRTs) { if (rt > rtSegs.Last()) { basepeak.RTsegments.Add(rtSegs.Count() - 1); } else if (rtSegs.Count() > 1 && rt < rtSegs[1]) { basepeak.RTsegments.Add(0); } else { for (int segmentboundary = 2; segmentboundary < rtSegs.Count(); segmentboundary++) { if (rt > rtSegs[segmentboundary - 1] && rt < rtSegs[segmentboundary]) { basepeak.RTsegments.Add(segmentboundary - 1); segmentboundary = rtSegs.Count();//move to the next bpkRT } } } } } double experimentWideMS2TICSquared = 0; //dividing ms2scans into segments of RT foreach (MzmlParser.Scan scan in run.Ms2Scans) { //if the scan starttime falls into the rtsegment, give it the correct rtsegment number //We assign to the segmentdivider below. So if >a and <b, it is assigned to segment a. if (scan.ScanStartTime > rtSegs.Last())//If the scan is after the last segment divider, it falls into the last segment { scan.RTsegment = rtSegs.Count() - 1; } else if (rtSegs.Count() > 1 && scan.ScanStartTime < rtSegs[1])//If the scan is before the second segment divider it should fall in the first segment. (assuming that the user has selected to have more than one segment) { scan.RTsegment = 0; } else { for (int segmentboundary = 2; segmentboundary < rtSegs.Count(); segmentboundary++) //If the scan is not in the first or last segment { if (scan.ScanStartTime > rtSegs[segmentboundary - 1] && scan.ScanStartTime < rtSegs[segmentboundary]) // If the scan is larger than the previous boundary and smaller than this boundary, assign to the previous segment. { scan.RTsegment = segmentboundary - 1; } } } experimentWideMS2TICSquared += Math.Pow(scan.TotalIonCurrent, 2); } //dividing ms1scans into segments of RT foreach (MzmlParser.Scan scan in run.Ms1Scans) { if (scan.ScanStartTime > rtSegs.Last())//If the scan is after the last segment divider, it falls into the last segment { scan.RTsegment = rtSegs.Count() - 1; } else if (rtSegs.Count() > 1 && scan.ScanStartTime < rtSegs[1])//If the scan is before the second segment divider it should fall in the first segment. (assuming that the user has selected to have more than one segment) { scan.RTsegment = 0; } else { for (int segmentboundary = 2; segmentboundary < rtSegs.Count(); segmentboundary++) //If the scan is not in the first or last segment { if (scan.ScanStartTime > rtSegs[segmentboundary - 1] && scan.ScanStartTime < rtSegs[segmentboundary]) // If the scan is larger than the previous boundary and smaller than this boundary, assign to the previous segment. { scan.RTsegment = segmentboundary - 1; } } } } //Retrieve TICChange metrics and divide into rtsegs List <double> ticChange50List = new List <double>(); List <double> ticChangeIqrList = new List <double>(); var tempTic = run.Ms2Scans.OrderBy(x => x.ScanStartTime).GroupBy(x => x.RTsegment).Select(d => d.Select(g => g.TotalIonCurrent).ToList()); double magnitude = Math.Pow(experimentWideMS2TICSquared, 0.5); for (int i = 0; i < tempTic.Count(); i++) { var temp = tempTic.ElementAt(i); List <double> tempList = new List <double>(); for (int j = 1; j < temp.Count(); j++) { tempList.Add(Math.Abs(temp.ElementAt(j) - temp.ElementAt(j - 1)) / magnitude);//Normalised to TIC magnitude. } tempList.Sort(); ticChange50List.Add(tempList.Average()); if (tempList.Count() > 4) { ticChangeIqrList.Add(InterQuartileRangeCalculator.CalcIQR(tempList)); } else { logger.Error("There are only {0} MS2Scans in this segment, which is too few to calculate the IQR of the TIC Change. This value has been set to zero.", tempTic.Count()); ticChangeIqrList.Add(0); } } //Calculations for peakprecision MS2: var meanIntensityOfAllBpks = run.BasePeaks.Select(x => x.Intensities.Sum()).Average(); var meanMzOfAllBpks = run.BasePeaks.Select(x => x.Mz).Average(); //Calculations for peakprecision MS1: //double mIMS1Bpks; //if (run.Ms1Scans.Count()>0) mIMS1Bpks = run.Ms1Scans.Select(x => x.BasePeakIntensity).Average(); //var mMMS1Bpks = run.Ms1Scans.Select(x => x.BasePeakMz).Average(); List <double> peakWidths = new List <double>(); List <double> TailingFactor = new List <double>(); List <double> peakCapacity = new List <double>(); List <double> peakPrecision = new List <double>(); List <double> ms1PeakPrecision = new List <double>(); List <int> ms1Density = new List <int>(); List <int> ms2Density = new List <int>(); List <double> cycleTime = new List <double>(); List <double> ms1TicTotal = new List <double>(); List <double> Ms2TicTotal = new List <double>(); for (int segment = 0; segment < division; segment++) { List <double> peakWidthsTemp = new List <double>(); List <double> peakSymTemp = new List <double>(); List <double> fullWidthBaselinesTemp = new List <double>(); List <double> peakPrecisionTemp = new List <double>(); foreach (MzmlParser.BasePeak basepeak in run.BasePeaks) { for (int i = 0; i < basepeak.RTsegments.Count(); i++) { if (basepeak.RTsegments[i] == segment) { peakWidthsTemp.Add(basepeak.FWHMs[i]); peakSymTemp.Add(basepeak.Peaksyms[i]); peakPrecisionTemp.Add(basepeak.Intensities[i] / (meanIntensityOfAllBpks * Math.Pow(2, meanMzOfAllBpks / basepeak.Mz))); fullWidthBaselinesTemp.Add(basepeak.FullWidthBaselines[i]); } } } List <double> firstScansOfCycle = new List <double>(); List <double> lastScansOfCycle = new List <double>(); List <double> difference = new List <double>(); double ms1TicTotalTemp = 0; List <int> ms1DensityTemp = new List <int>(); List <double> ms1PeakPrecisionTemp = new List <double>(); foreach (MzmlParser.Scan scan in run.Ms1Scans.OrderBy(x => x.ScanStartTime)) { if (scan.RTsegment == segment) { ms1PeakPrecisionTemp.Add(scan.BasePeakIntensity / (meanIntensityOfAllBpks * Math.Pow(2, meanMzOfAllBpks / scan.BasePeakMz))); ms1DensityTemp.Add(scan.Density); ms1TicTotalTemp += scan.TotalIonCurrent; } } int minNumberMS1Or2 = 0; //To get scan speed for both ms1 and ms2 we have to also scan through ms2: if (run.Ms1Scans.Count() > 1) { lastScansOfCycle = run.Ms2Scans.Where(x => x.RTsegment == segment).GroupBy(g => g.Cycle).Select(x => x.Max(y => y.ScanStartTime)).ToList(); firstScansOfCycle = run.Ms1Scans.Where(x => x.RTsegment == segment).Select(y => y.ScanStartTime).ToList(); } else { lastScansOfCycle = run.Ms2Scans.Where(x => x.RTsegment == segment).GroupBy(g => g.Cycle).Select(x => x.Max(y => y.ScanStartTime)).ToList(); firstScansOfCycle = run.Ms2Scans.Where(x => x.RTsegment == segment).GroupBy(g => g.Cycle).Select(x => x.Min(y => y.ScanStartTime)).ToList(); } minNumberMS1Or2 = Math.Min(lastScansOfCycle.Count(), firstScansOfCycle.Count()); for (int i = 0; i < minNumberMS1Or2; i++) { difference.Add(lastScansOfCycle[i] - firstScansOfCycle[i]); } cycleTime.Add(difference.Average() * 60); List <int> ms2DensityTemp = run.Ms2Scans.Where(x => x.RTsegment == segment).Select(x => x.Density).ToList(); double ms2TicTotalTemp = run.Ms2Scans.Where(x => x.RTsegment == segment).Select(x => x.TotalIonCurrent).Sum(); if (peakWidthsTemp.Count > 0) { peakWidths.Add(peakWidthsTemp.Average()); TailingFactor.Add(peakSymTemp.Average()); peakCapacity.Add(rtSegment / fullWidthBaselinesTemp.Average());//PeakCapacity is calculated as per Dolan et al.,2009, PubMed 10536823); peakPrecision.Add(peakPrecisionTemp.Average()); } else { peakWidths.Add(0); TailingFactor.Add(0); peakCapacity.Add(0); peakPrecision.Add(0); } if (ms1PeakPrecisionTemp.Count > 0) { ms1PeakPrecision.Add(ms1PeakPrecisionTemp.Average()); ms1Density.Add(Convert.ToInt32(Math.Ceiling(ms1DensityTemp.Average()))); } else { ms1PeakPrecision.Add(0); ms1Density.Add(0); } ms2Density.Add(Convert.ToInt32(Math.Round(ms2DensityTemp.Average(), 0))); ms1TicTotal.Add(ms1TicTotalTemp); Ms2TicTotal.Add(ms2TicTotalTemp); } RTMetrics rtMetrics = new RTMetrics(ms1TicTotal, Ms2TicTotal, cycleTime, ticChange50List, ticChangeIqrList, ms1Density, ms2Density, peakWidths, TailingFactor, peakCapacity, peakPrecision, ms1PeakPrecision, segmentBoundaries); return(rtMetrics); }
public SwathMetrics GroupBySwath(MzmlParser.Run run) { //Create list of target isolationwindows to serve as swathnumber List <double> swathTargets = new List <double>(); swathTargets = run.Ms2Scans.OrderBy(y => y.ScanStartTime).Select(x => x.IsolationWindowTargetMz).Distinct().ToList(); double totalTIC = 0; foreach (var scan in run.Ms2Scans) { totalTIC += scan.TotalIonCurrent; } //Loop through every swath of a certain swathNumber: List <int> numOfSwathPerGroup = new List <int>(); List <double> TICs = new List <double>(); List <double> swDensity = new List <double>(); List <double> swDensity50 = new List <double>(); List <double> swDensityIQR = new List <double>(); List <double> mzTargetRange = new List <double>(); List <double> averageMzTargetRange = new List <double>(); List <double> SwathProportionOfTotalTIC = new List <double>(); List <double> TotalSwathProportionPredictedSingleCharge = new List <double>(); List <double> SwathProportionPredictedSingleChargeAvg = new List <double>(); //Loop through all the swaths of the same number and add to for (int swathNumber = 0; swathNumber < swathTargets.Count(); swathNumber++) { int track = 0; double TICthisSwath = 0; var orderedMS2Scans = run.Ms2Scans.OrderBy(s => s.ScanStartTime) .Where(x => x.MsLevel == 2 && x.IsolationWindowTargetMz == swathTargets[swathNumber]); foreach (var scan in orderedMS2Scans) { mzTargetRange.Add(scan.IsolationWindowUpperOffset + scan.IsolationWindowLowerOffset); TICthisSwath = TICthisSwath + scan.TotalIonCurrent; swDensity.Add(scan.Density); TotalSwathProportionPredictedSingleCharge.Add(scan.ProportionChargeStateOne); //The chargestate one's we pick up is where there is a match for M+1. Therefore we need to double it to add the M. track++; } averageMzTargetRange.Add(mzTargetRange.Average()); numOfSwathPerGroup.Add(track); TICs.Add(TICthisSwath); TICthisSwath = 0; SwathProportionPredictedSingleChargeAvg.Add(TotalSwathProportionPredictedSingleCharge.Average()); TotalSwathProportionPredictedSingleCharge.Clear(); swDensity.Sort(); swDensity50.Add(Math.Truncate(Math.Ceiling(swDensity.Average()))); swDensityIQR.Add(Math.Truncate(Math.Ceiling(InterQuartileRangeCalculator.CalcIQR(swDensity)))); swDensity.Clear(); mzTargetRange.Clear(); } for (int num = 0; num < swathTargets.Count(); num++) { SwathProportionOfTotalTIC.Add(TICs[num] / totalTIC); } SwathMetrics swathMetrics = new SwathMetrics(swathTargets, totalTIC, numOfSwathPerGroup, averageMzTargetRange, TICs, swDensity50, swDensityIQR, SwathProportionOfTotalTIC, SwathProportionPredictedSingleChargeAvg); return(swathMetrics); }