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