@@ -98,7 +98,7 @@ class Atom(Vertex):
9898 `spinMultiplicity` ``short`` The spin multiplicity of the atom
9999 `charge` ``short`` The formal charge of the atom
100100 `label` ``str`` A string label that can be used to tag individual atoms
101- `coords`
101+ `coords` ``numpy array`` The (x,y,z) coordinates in Angstrom
102102 `lonePairs` ``short`` The number of lone electron pairs
103103 =================== =================== ====================================
104104
@@ -107,7 +107,7 @@ class Atom(Vertex):
107107 e.g. ``atom.symbol`` instead of ``atom.element.symbol``.
108108 """
109109
110- def __init__ (self , element = None , radicalElectrons = 0 , spinMultiplicity = 1 , charge = 0 , label = '' , lonePairs = 0 ):
110+ def __init__ (self , element = None , radicalElectrons = 0 , spinMultiplicity = 1 , charge = 0 , label = '' , lonePairs = 0 , coords = None ):
111111 Vertex .__init__ (self )
112112 if isinstance (element , str ):
113113 self .element = elements .__dict__ [element ]
@@ -119,7 +119,7 @@ def __init__(self, element=None, radicalElectrons=0, spinMultiplicity=1, charge=
119119 self .label = label
120120 self .atomType = None
121121 self .lonePairs = lonePairs
122- self .coords = list ()
122+ self .coords = coords
123123
124124 def __str__ (self ):
125125 """
@@ -829,6 +829,51 @@ def deleteHydrogens(self):
829829 for atom in hydrogens :
830830 self .removeAtom (atom )
831831
832+ def connectTheDots (self ):
833+ """
834+ Delete all bonds, and set them again based on the Atoms' coords.
835+ Does not detect bond type.
836+ """
837+ cython .declare (criticalDistance = float , i = int , atom1 = Atom , atom2 = Atom ,
838+ bond = Bond , atoms = list , zBoundary = float )
839+ # groupBond=GroupBond,
840+ self ._fingerprint = None
841+
842+ atoms = self .vertices
843+
844+ # Ensure there are coordinates to work with
845+ for atom in atoms :
846+ assert atom .coords != None
847+
848+ # If there are any bonds, remove them
849+ for atom1 in atoms :
850+ for bond in self .getBonds (atom1 ):
851+ self .removeEdge (bond )
852+
853+ # Sort atoms by distance on the z-axis
854+ sortedAtoms = sorted (atoms , key = lambda x : x .coords [2 ])
855+
856+ for i , atom1 in enumerate (sortedAtoms ):
857+ for atom2 in sortedAtoms [i + 1 :]:
858+ # Set upper limit for bond distance
859+ criticalDistance = (atom1 .element .covRadius + atom2 .element .covRadius + 0.45 )** 2
860+
861+ # First atom that is more than 4.0 Anstroms away in the z-axis, break the loop
862+ # Atoms are sorted along the z-axis, so all following atoms should be even further
863+ zBoundary = (atom1 .coords [2 ] - atom2 .coords [2 ])** 2
864+ if zBoundary > 16.0 :
865+ break
866+
867+ distanceSquared = sum ((atom1 .coords - atom2 .coords )** 2 )
868+
869+ if distanceSquared > criticalDistance or distanceSquared < 0.40 :
870+ continue
871+ else :
872+ # groupBond = GroupBond(atom1, atom2, ['S','D','T','B'])
873+ bond = Bond (atom1 , atom2 , 'S' )
874+ self .addBond (bond )
875+ self .updateAtomTypes ()
876+
832877 def updateAtomTypes (self ):
833878 """
834879 Iterate through the atoms in the structure, checking their atom types
@@ -1153,6 +1198,44 @@ def fromAdjacencyList(self, adjlist, saturateH=False):
11531198 self .updateAtomTypes ()
11541199
11551200 return self
1201+
1202+ def fromXYZ (self , atomicNums , coordinates ):
1203+ """
1204+ Create an RMG molecule from a list of coordinates and a corresponding
1205+ list of atomic numbers. These are typically received from CCLib and the
1206+ molecule is sent to `ConnectTheDots` so will only contain single bonds.
1207+ """
1208+
1209+ _rdkit_periodic_table = elements .GetPeriodicTable ()
1210+
1211+ for i , atNum in enumerate (atomicNums ):
1212+ atom = Atom (_rdkit_periodic_table .GetElementSymbol (int (atNum )))
1213+ atom .coords = coordinates [i ]
1214+ self .addAtom (atom )
1215+ return self .connectTheDots ()
1216+
1217+ def toSingleBonds (self ):
1218+ """
1219+ Returns a copy of the current molecule, consisting of only single bonds.
1220+
1221+ This is useful for isomorphism comparison against something that was made
1222+ via fromXYZ, which does not attempt to perceive bond orders
1223+ """
1224+ cython .declare (atom1 = Atom , atom2 = Atom , bond = Bond , newMol = Molecule , atoms = list , mapping = dict )
1225+
1226+ newMol = Molecule ()
1227+ atoms = self .atoms
1228+ mapping = {}
1229+ for atom1 in atoms :
1230+ atom2 = newMol .addAtom (Atom (atom1 .element ))
1231+ mapping [atom1 ] = atom2
1232+
1233+ for atom1 in atoms :
1234+ for atom2 in atom1 .bonds :
1235+ bond = Bond (mapping [atom1 ], mapping [atom2 ], 'S' )
1236+ newMol .addBond (bond )
1237+ newMol .updateAtomTypes ()
1238+ return newMol
11561239
11571240 def toInChI (self ):
11581241 """
0 commit comments