public Pattern Calculate(FormMap fm, double limit, long charge)
        {
            Pattern tmp    = new Pattern();
            Pattern result = new Pattern();

            result.Add(new Peak()
            {
                Mz = 0.0, Intensity = 1.0
            });

            foreach (var i in fm)
            {
                int           atom_index = i.Key;
                SuperAtomList sal        = sad[atom_index];
                int           n          = i.Value;
                int           j          = 0;
                while (n > 0)
                {
                    int sz = sal.Count;
                    if (j == sz)
                    {
                        sal.Add(new Pattern());
                        convolute_basic(sal[j], sal[j - 1], sal[j - 1]);
                        Prune(sal[j], limit);
                    }
                    if ((n & 1) == 1)
                    { // digit is 1, convolute result
                        convolute_basic(tmp, result, sal[j]);
                        Prune(tmp, limit);
                        result.Clear();
                        result.AddRange(tmp);
                    }
                    n >>= 1;
                    j++;
                }
            }

            // take charge into account
            foreach (var p in result)
            {
                if (charge > 0)
                {
                    p.Mz = p.Mz / Math.Abs(charge) - ELECTRON_MASS;
                }
                else if (charge < 0)
                {
                    p.Mz = p.Mz / Math.Abs(charge) + ELECTRON_MASS;
                }
            }

            if (result.Count == 0)
            {
                throw new Exception("Calculate profile failed");
            }
            return(result);
        }
        public EmassCalculator(string filename)
        {
            if (!File.Exists(filename))
            {
                throw new FileNotFoundException(filename);
            }

            IsotopicMap = new ElemMap();

            using (StreamReader f = new StreamReader(filename))
            {
                sad.Clear();
                IsotopicMap.Clear();

                string line;
                int    elemindex = 0;
                int    state     = 0;
                while ((line = f.ReadLine()) != null)
                {
                    string element;
                    switch (state)
                    {
                    case 0: // new element
                        var m0 = eleReg.Match(line);
                        element = m0.Groups[1].Value;
                        IsotopicMap[element] = elemindex;
                        var pkl = new Pattern();
                        var sal = new SuperAtomList();
                        sal.Add(pkl);
                        sad.Add(sal);
                        elemindex++;
                        state = 1;
                        break;

                    case 1: // isotope
                        var m1 = eleReg.Match(line);
                        if (m1.Success)
                        {
                            Peak p = new Peak();
                            p.Mz        = MyConvert.ToDouble(m1.Groups[1].Value);
                            p.Intensity = MyConvert.ToDouble(m1.Groups[2].Value);
                            Pattern idist = sad.Last().First();
                            // fill the gaps in the patterns with zero abundancy peaks
                            if (idist.Count > 0)
                            {
                                double prevmass = idist.Last().Mz;
                                for (int i = 0; i < (int)(p.Mz - prevmass - 0.5); i++)
                                {
                                    Peak filler = new Peak();
                                    filler.Mz        = DUMMY_MASS;
                                    filler.Intensity = 0;
                                    idist.Add(filler);
                                }
                            }
                            // insert the peak
                            idist.Add(p);
                        }
                        else
                        {
                            state = 0;
                        }
                        break;
                    }
                }
            }
        }