public MS3Item Build(List <MS3Item> g)
        {
            var result = new MS3Item();

            result.PrecursorMZ = g.Sum(m => m.PrecursorMZ * m.Sum(p => p.Intensity)) / g.Sum(m => m.Sum(p => p.Intensity));

            List <MS3Peak> peaks = new List <MS3Peak>();

            for (int i = 0; i < g.Count; i++)
            {
                peaks.AddRange(from peak in g[i]
                               select new MS3Peak()
                {
                    Mz = peak.Mz, Intensity = peak.Intensity, Tag = i, CombinedCount = peak.CombinedCount
                });
            }
            peaks.Sort((m1, m2) => m1.Mz.CompareTo(m2.Mz));

            //group peak by m/z
            var pgroups    = new List <List <MS3Peak> >();
            var currentPkl = new List <MS3Peak>();

            currentPkl.Add(peaks.First());
            for (int i = 1; i < peaks.Count; i++)
            {
                foreach (var peak in currentPkl)
                {
                    var diff    = Math.Abs(peaks[i].Mz - peak.Mz);
                    var ppmdiff = PrecursorUtils.mz2ppm(peak.Mz, diff);
                    if (ppmdiff <= fragmentPPMTolerance)
                    {
                        currentPkl.Add(peaks[i]);
                        break;
                    }
                }

                if (peaks[i] != currentPkl.Last())
                {
                    pgroups.Add(currentPkl);
                    currentPkl = new List <MS3Peak>();
                    currentPkl.Add(peaks[i]);
                }
            }
            pgroups.Add(currentPkl);

            result.Clear();
            foreach (var pg in pgroups)
            {
                if (pg.Count == 1)
                {
                    result.Add(pg.First());
                }
                else
                {
                    //for each spectrum, only the peak with most intensity will be used for merge
                    var waiting = (from t in pg.GroupBy(m => m.Tag)
                                   select(from tt in t
                                          orderby tt.Intensity descending
                                          select tt).First()).ToArray();

                    var combinedpeak = new MS3Peak()
                    {
                        Mz            = waiting.Sum(m => m.Mz * m.Intensity) / waiting.Sum(m => m.Intensity),
                        Intensity     = waiting.Sum(m => m.Intensity),
                        CombinedCount = waiting.Sum(m => m.CombinedCount)
                    };

                    result.Add(combinedpeak);
                }
            }

            result.CombinedCount = g.Count;

            if (result.Count > maxPeakCount)
            {
                result.Sort((m1, m2) =>
                {
                    var res = m2.CombinedCount.CompareTo(m1.CombinedCount);
                    if (res == 0)
                    {
                        res = m2.Intensity.CompareTo(m1.Intensity);
                    }
                    return(res);
                });

                for (int i = result.Count - 1; i >= maxPeakCount; i--)
                {
                    result.RemoveAt(i);
                }

                result.SortByMz();
            }

            return(result);
        }
        public List <MS2Item> ReadFromFile(string fileName)
        {
            if (!File.Exists(fileName))
            {
                throw new FileNotFoundException(fileName);
            }

            XElement root = XElement.Load(fileName);

            List <MS2Item> result = new List <MS2Item>();

            foreach (var ms2ele in root.Elements("MS2"))
            {
                var item = new MS2Item();
                result.Add(item);

                item.CombinedCount = int.Parse(ms2ele.Attribute("PKL").Value);
                item.Precursor     = double.Parse(ms2ele.Attribute("MZ").Value);
                item.Charge        = int.Parse(ms2ele.Attribute("Z").Value);
                item.FileScans     = (from ele in ms2ele.Elements("FileScan")
                                      let exp = ele.Attribute("F").Value
                                                let firstscan = int.Parse(ele.Attribute("S").Value)
                                                                select new SequestFilename(exp, firstscan, firstscan, item.Charge, string.Empty)).ToList();
                item.Score       = double.Parse(ms2ele.Attribute("Score").Value);
                item.ExpectValue = double.Parse(ms2ele.Attribute("ExpectValue").Value);
                if (ms2ele.Attribute("Seq") != null)
                {
                    item.Peptide = ms2ele.Attribute("Seq").Value;
                }
                if (ms2ele.Attribute("Mod") != null)
                {
                    item.Modification = ms2ele.Attribute("Mod").Value;
                }
                if (ms2ele.Attribute("Proteins") != null)
                {
                    item.Proteins = ms2ele.Attribute("Proteins").Value;
                }
                foreach (var ele in ms2ele.Elements("TerminalLoss"))
                {
                    item.TerminalLoss.Add(new TerminalLossItem(bool.Parse(ele.Attribute("IsNterminal").Value), ele.Attribute("Seq").Value, double.Parse(ele.Attribute("MZ").Value)));
                }

                foreach (var ms3ele in ms2ele.Elements("MS3"))
                {
                    var ms3 = new MS3Item();
                    item.MS3Spectra.Add(ms3);

                    if (item.CombinedCount > 1)
                    {
                        ms3.CombinedCount = int.Parse(ms3ele.Attribute("PKL").Value);
                    }
                    else
                    {
                        ms3.CombinedCount = 1;
                    }
                    ms3.PrecursorMZ = double.Parse(ms3ele.Attribute("MZ").Value);
                    foreach (var pEle in ms3ele.Elements("P"))
                    {
                        var peak = new MS3Peak();
                        ms3.Add(peak);

                        peak.Mz        = double.Parse(pEle.Attribute("MZ").Value);
                        peak.Intensity = double.Parse(pEle.Attribute("I").Value);
                        if (ms3.CombinedCount > 1)
                        {
                            peak.CombinedCount = int.Parse(pEle.Attribute("PKL").Value);
                        }
                        else
                        {
                            peak.CombinedCount = 1;
                        }
                    }
                }
            }

            return(result);
        }