void IScanConsumer <Scan, Run <Scan> > .Notify(Scan scan, float[] mzs, float[] intensities, Run <Scan> run) { scan.IsolationWindowLowerBoundary = scan.IsolationWindowTargetMz - scan.IsolationWindowLowerOffset; scan.IsolationWindowUpperBoundary = scan.IsolationWindowTargetMz + scan.IsolationWindowUpperOffset; if (intensities.Count() == 0) { intensities = FillZeroArray(intensities); mzs = FillZeroArray(mzs); logger.Debug("Empty binary array for a MS{0} scan in cycle number: {1}. The empty scans have been filled with zero values.", scan.MsLevel, scan.Cycle); run.MissingScans++; } var spectrum = intensities.Select((x, i) => new SpectrumPoint(x, mzs[i], (float)scan.ScanStartTime)).Where(x => x.Intensity >= run.AnalysisSettings.MinimumIntensity).ToList(); //Predicted singly charged proportion: //The theory is that an M and M+1 pair are singly charged so we are very simply just looking for occurences where two ions are 1 mz apart (+-massTolerance) //We therefore create an array cusums that accumulates the difference between ions, so for every ion we calculate the distance between that ion //and the previous and add that to each of the previous ions' cusum of differences. If the cusum of an ion overshoots 1 +massTolerance, we stop adding to it, if it reaches our mark we count it and stop adding to it List <int> indexes = new List <int>(); float[] cusums = new float[mzs.Length]; int movingPoint = 0; double minimum = 1 - 0.001; double maximum = 1 + 0.001; for (int i = 1; i < mzs.Length; i++) { float distance = mzs[i] - mzs[i - 1]; bool matchedWithLower = false; for (int ii = movingPoint; ii < i; ii++) { cusums[ii] += distance; if (cusums[ii] < minimum) { continue; } else if (cusums[ii] > minimum && cusums[ii] < maximum) { if (!matchedWithLower)//This is to try and minimise false positives where for example if you have an array: 351.14, 351.15, 352.14 all three get chosen. { indexes.Add(i); indexes.Add(movingPoint); } movingPoint += 1; matchedWithLower = true; continue; } else if (cusums[ii] > maximum) { movingPoint += 1; } } } int distinct = indexes.Distinct().Count(); int len = mzs.Length; scan.ProportionChargeStateOne = distinct / (double)len; if (scan.TotalIonCurrent == 0) { scan.TotalIonCurrent = intensities.Sum(); TicNotFound = true; } scan.Spectrum = new Spectrum() { SpectrumPoints = spectrum }; scan.IsolationWindowLowerBoundary = scan.IsolationWindowTargetMz - scan.IsolationWindowLowerOffset; scan.IsolationWindowUpperBoundary = scan.IsolationWindowTargetMz + scan.IsolationWindowUpperOffset; scan.Density = spectrum.Count(); scan.BasePeakIntensity = intensities.Max(); scan.BasePeakMz = mzs[Array.IndexOf(intensities, intensities.Max())]; float basepeakIntensity; if (intensities.Count() > 0) { // TODO: This approach requires two scans across intensities plus converting intensities to a List; is there a simpler approach involving a single scan in a for-next loop? basepeakIntensity = intensities.Max(); int maxIndex = intensities.ToList().IndexOf(basepeakIntensity); double mz = mzs[maxIndex]; AtomicallyRecordBasePeakAndRT(new DoubleSpectrumPoint(basepeakIntensity, mz, scan.ScanStartTime), run); } else { basepeakIntensity = 0; } //Extract info for Basepeak chromatograms bool irt = run.AnalysisSettings.IrtLibrary != null; if (irt) { FindIrtPeptideCandidates(scan, run, spectrum); } }
private void FindMs2IsolationWindows(Run <Scan> run) { run.IsolationWindows = run.Ms2Scans.Select(x => (x.IsolationWindowTargetMz - x.IsolationWindowLowerOffset, x.IsolationWindowTargetMz + x.IsolationWindowUpperOffset)).Distinct().ToList(); logger.Debug("{0} isolation windows detected: min {1} max {2}", run.IsolationWindows.Count, run.IsolationWindows.Min(x => x.Item2 - x.Item1), run.IsolationWindows.Max(x => x.Item2 - x.Item1)); }