Пример #1
0
        // Returns atom interactions between groups of atoms. Will ignore interactions between atoms within each group.
        // Uses KDTree to find atoms within a certain distance and then calculates the forces on those atoms.
        public List <AtomInteraction> GetAllInteractions(List <Atom> molecule1Atoms, List <Vector3> molecule1AtomPositions, List <Atom> molecule2Atoms, List <Vector3> molecule2AtomPositions, Gradient repulsiveGradient, Gradient strongAttractiveGradient, Gradient weakAttractiveGradient, int processorCores = 1)
        {
            if (molecule1Atoms == null || molecule1AtomPositions == null || molecule1Atoms.Count != molecule1AtomPositions.Count)
            {
                Debug.Log("Interactions calculator, Molecule 1 atoms count and molecule 1 atom positions count don't match");
                return(new List <AtomInteraction>());
            }

            if (molecule2Atoms == null || molecule2AtomPositions == null || molecule2Atoms.Count != molecule2AtomPositions.Count)
            {
                Debug.Log("Interactions calculator, Molecule 2 atoms count and molecule 2 atom positions count don't match");
                return(new List <AtomInteraction>());
            }

            KdTree <float, int> molecule2AtomTree = new KdTree <float, int>(3, new FloatMath());

            for (int i = 0; i < molecule2Atoms.Count; i++)
            {
                Vector3 molecule2AtomPosition = molecule2AtomPositions[i];
                molecule2AtomTree.Add(new float[] { molecule2AtomPosition.x, molecule2AtomPosition.y, molecule2AtomPosition.z }, i);
            }

            List <AtomInteraction> interactions = new List <AtomInteraction>();

            for (int i = 0; i < molecule1Atoms.Count; i++)
            {
                Atom    atom         = molecule1Atoms[i];
                Vector3 atomPosition = molecule1AtomPositions[i];

                KdTreeNode <float, int>[] interactingAtoms = molecule2AtomTree.RadialSearch(new float[] { atomPosition.x, atomPosition.y, atomPosition.z }, maxInteractionDistance, maxInteractionsPerAtom);

                foreach (KdTreeNode <float, int> node in interactingAtoms)
                {
                    Atom interactingAtom = molecule2Atoms[node.Value];

                    Vector3 interactingAtomPosition = molecule2AtomPositions[node.Value];

                    // get distance between atoms
                    float deltaX   = interactingAtomPosition.x - atomPosition.x;
                    float deltaY   = interactingAtomPosition.y - atomPosition.y;
                    float deltaZ   = interactingAtomPosition.z - atomPosition.z;
                    float distance = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);

                    AtomInteraction interaction = new AtomInteraction()
                    {
                        Atom1    = atom,
                        Atom2    = interactingAtom,
                        Distance = distance,
                    };

                    SetLennardJonesPotential(interaction);
                    SetElecrostaticEnergy(interaction);
                    SetInteractionType(interaction, repulsiveGradient, strongAttractiveGradient, weakAttractiveGradient);

                    interactions.Add(interaction);
                }
            }

            return(interactions);
        }
        private void findBonds(object argument)
        {
            List <int> threadAtoms = (List <int>)argument;

            foreach (int atomIndex in threadAtoms)
            {
                Atom atom = atoms[atomIndex];

                KdTreeNode <float, int>[] bondAtoms = tree.RadialSearch(new float[] { atom.Position.x, atom.Position.y, atom.Position.z }, BondLengths.MaximumLengthAllElements, BondLengths.MaxBondsPerAtom);

                foreach (KdTreeNode <float, int> bondAtomNode in bondAtoms)
                {
                    // atom can't bond to itself
                    // (tree search always finds the supplied atom as well since it's only searching from a position, not an atom)
                    if (atomIndex == bondAtomNode.Value)
                    {
                        continue;
                    }

                    string bondKey = getBondKey(atom.Index, bondAtomNode.Value);

                    // check it hasn't been added previously (i.e. bond in reverse).
                    if (!addedBonds.Contains(bondKey))
                    {
                        Atom bondAtom = atoms[bondAtomNode.Value];

                        // get the maximum bond length for this bond

                        // first try a lookup
                        float maxBondLength;
                        if (!maxBondLengths.TryGetValue(new ElementPair(atom.Element, bondAtom.Element), out maxBondLength))
                        {
                            // if lookup fails use defaults
                            if (atom.Element == Element.H || bondAtom.Element == Element.H)
                            {
                                maxBondLength = BondLengths.MaximumLengthHydrogen;
                            }
                            else
                            {
                                maxBondLength = BondLengths.MaximumLengthAllElements;
                            }
                        }

                        // if the maxBondLength is lower than the search radius in the KDTree search
                        // then calculate the bond length between the atoms and check it doesn't exceed maxBondLength
                        if (maxBondLength < BondLengths.MaximumLengthAllElements)
                        {
                            if (atomDistance(atom, bondAtom) > maxBondLength)
                            {
                                continue;
                            }
                        }

                        lock (bondAddLock) {
                            bonds.Add(++bondID, new Bond(atomIndex, bondAtomNode.Value));
                            addedBonds.Add(bondKey);
                            //addBond(atom.Index, bondAtomNode.Value);
                        }
                    }
                }
            }
        }