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);
        }