// same as above method but allows for custom max bond lengths
        public Dictionary <int, Bond> CalculateBonds(Dictionary <int, Atom> atoms, Dictionary <ElementPair, float> maxBondLengths, int processorCores)
        {
            this.atoms          = atoms;
            this.maxBondLengths = maxBondLengths;

            bonds      = new Dictionary <int, Bond>();
            tree       = new KdTree <float, int>(3, new FloatMath());
            addedBonds = new HashSet <string>();
            bondID     = 0;

            UnityEngine.Debug.Log("Generating Atom Tree");
            Stopwatch watch = new Stopwatch();

            watch.Start();

            foreach (KeyValuePair <int, Atom> atom in atoms)
            {
                tree.Add(new float[] { atom.Value.Position.x, atom.Value.Position.y, atom.Value.Position.z }, atom.Key);
            }

            watch.Stop();
            UnityEngine.Debug.Log("Generated Atom Tree: " + watch.ElapsedMilliseconds.ToString("N2"));
            watch.Reset();
            watch.Start();

            //for each atom find all linked atoms

            List <Thread> threadList  = new List <Thread>();
            List <int>    atomIndexes = atoms.Keys.ToList();
            int           threadCount = processorCores - 1;

            if (threadCount <= 0)
            {
                threadCount = 1;
            }

            int maxAtomsPerThread = Mathf.Max(1, atomIndexes.Count / threadCount);

            for (int i = 0; i < atomIndexes.Count; i += maxAtomsPerThread)
            {
                int threadAtomCount = maxAtomsPerThread;
                if (i > atomIndexes.Count - threadAtomCount - 1)
                {
                    threadAtomCount = atomIndexes.Count - i - 1;
                }

                List <int> threadAtoms = atomIndexes.GetRange(i, threadAtomCount);

                Thread newThread = new Thread(findBonds);
                newThread.Start(threadAtoms);
                threadList.Add(newThread);
            }

            foreach (var thread in threadList)
            {
                thread.Join();
            }

            watch.Stop();
            UnityEngine.Debug.Log("Generated Bond Results: " + watch.ElapsedMilliseconds.ToString("N2"));
            watch.Reset();

            return(bonds.ToDictionary(entry => entry.Key, entry => entry.Value));
        }