def getSubstructureFromPath(refmol: Molecule, path: np.ndarray) -> Molecule: """Create a molecules object from a substructure of given molecule.""" # initialize refat = refmol.get_atomic_numbers() refxyz = refmol.get_positions() # atoms from complex excluding old substrate atoms = [] for elem in path: atom = Atom(symbol=refat[elem], position=refxyz[elem, :]) atoms.append(atom) # create molecule from atoms return Molecule(symbols=atoms)
def getClassicalSterimol(mol: Molecule, origin: int, partner: int): """Verloop definitions for L, B1, and B5 steric parameter. We apply kallisto van der Waals radii.""" # initialize coordinates coords = mol.get_positions() # get number of atoms nat = mol.get_number_of_atoms() # get van der Waals radii in Bohr vdw = np.zeros(shape=(nat, ), dtype=np.float64) vdw = mol.get_vdw(charge=0, vdwtype="rahm", scale=1) # shift all atoms wrt origin coords -= coords[origin] # extract vector origin -> attachted and normalize vector = np.zeros(shape=(3, ), dtype=np.float64) vector = coords[partner] - coords[origin] vector /= np.linalg.norm(vector) # align vector and x-axis xaxis = np.array([1, 0, 0]) dot = np.dot(vector, xaxis).reshape(1) + 1 # define zaxis and cover antiparallel case zaxis = np.array([0, 0, 1]) epsilon = 1e-06 if dot < epsilon: w = np.cross(vector, zaxis) if np.linalg.norm(w) < epsilon: w = np.cross(vector, xaxis) else: w = np.cross(vector, xaxis) # define quaternion q and normalize q = np.concatenate((w, dot)) q /= np.linalg.norm(q) # rotate coordinates according to q u = R.from_quat(q) coords = u.apply(coords) # project coordinates on vector vector = coords[partner] - coords[origin] unitVector = vector / np.linalg.norm(vector) # project coordinates on vectors vdw = np.vstack(vdw).reshape(-1) cvalues = np.dot(unitVector.reshape(1, -1), coords.T) projected = cvalues + vdw lval = np.max(projected) L = unitVector * lval L = L.reshape(-1) # B min and max values r = 1 slices = 360 theta = np.linspace(0, 2 * np.pi, slices) x = np.zeros(shape=(len(theta), ), dtype=np.float64) y = r * np.cos(theta) z = r * np.sin(theta) vectors = np.column_stack((x, y, z)) cvalues = np.dot(vectors, coords.T) projected = cvalues + vdw maxValues = np.max(projected, axis=1) bminVal = np.min(maxValues) bmaxVal = np.max(maxValues) return lval, bminVal, bmaxVal
def matchSubstrates( bonds: np.ndarray, new: Molecule, bondsNewSub: np.ndarray, old: Molecule, bondsOldSub, center: np.ndarray, ) -> np.ndarray: """Match substrates by root mean squared deviation measure.""" # check is central atom given centered = False count = 1 if center is not None: centered = True count = 2 newnat = new.get_number_of_atoms() newxyz = np.zeros(shape=(newnat, 3), dtype=np.float64) newxyz = new.get_positions() oldnat = old.get_number_of_atoms() oldxyz = np.zeros(shape=(oldnat, 3), dtype=np.float64) oldxyz = old.get_positions() # shift to first atom of old substrate shift = np.zeros(shape=(3, ), dtype=np.float64) shift = oldxyz[0, :] oldShift = shift oldxyz2 = np.zeros(shape=(oldnat, 3), dtype=np.float64) for i in range(oldnat): oldxyz2[i][:] = oldxyz[i][:] - shift # shift to first atom of new substrate shift = newxyz[0, :] newxyz2 = np.zeros(shape=(newnat, 3), dtype=np.float64) for i in range(newnat): newxyz2[i][:] = newxyz[i][:] - shift # covalent bonding partner in old substrate covOld = len(bondsOldSub[0][:]) # covalent bonding partner in new substrate covNew = len(bondsNewSub[0][:]) # Check for linear moleule case if covNew != 1: isNotLinear = True else: isNotLinear = False covOld += count covNew += count # get structures for RMSD alignment shiftOldSub = np.zeros(shape=(covOld, 3), dtype=np.float64) shiftOldSub[0, :] = oldxyz2[0, :] shiftNewSub = np.zeros(shape=(covNew, 3), dtype=np.float64) shiftNewSub[0, :] = newxyz2[0, :] # shift old substrate i = 0 for j in range(len(bondsOldSub[0][:])): i += 1 k = bondsOldSub[0][j] shiftOldSub[i, :] = oldxyz2[k, :] # shift new substrate i = 0 for j in range(len(bondsNewSub[0][:])): i += 1 k = bondsNewSub[0][j] shiftNewSub[i, :] = newxyz2[k, :] if centered: indexOld = covOld - 1 indexNew = covNew - 1 shiftOldSub[indexOld, :] = center - oldShift distRef = getDist(shiftOldSub[0, :], shiftOldSub[indexOld, :]) shiftNewSub[indexNew][:] = 0 shift = getNewSubstrateCenter(indexNew, shiftNewSub, distRef) bdim = np.minimum(covOld, covNew) print(bdim) if bdim >= 3: bdim = 3 b1xyz = np.zeros(shape=(bdim, 3), dtype=np.ndarray) b2xyz = np.zeros(shape=(bdim, 3), dtype=np.ndarray) indexOld = covOld - 1 indexNew = covNew - 1 b1xyz[0][:] = shiftOldSub[0][:] b1xyz[1][:] = shiftOldSub[1][:] b1xyz[2][:] = shiftOldSub[indexOld][:] b2xyz[0][:] = shiftNewSub[0][:] b2xyz[1][:] = shiftNewSub[1][:] b2xyz[2][:] = shiftNewSub[indexNew][:] else: bdim = 2 b1xyz = np.zeros(shape=(bdim, 3), dtype=np.ndarray) b2xyz = np.zeros(shape=(bdim, 3), dtype=np.ndarray) indexOld = covOld - 1 indexNew = covNew - 1 b1xyz[0][:] = shiftOldSub[0][:] b1xyz[1][:] = shiftOldSub[indexOld][:] b2xyz[0][:] = shiftNewSub[0][:] b2xyz[1][:] = shiftNewSub[indexNew][:] tmpxyz = np.zeros(shape=(newnat, 3), dtype=np.float64) outxyz = np.zeros(shape=(newnat, 3), dtype=np.float64) if isNotLinear: u = np.zeros(shape=(3, 3), dtype=np.float64) error = 0.0 # get RMSD value and rotation matrix error, u = rmsd(bdim, b2xyz, b1xyz) tmpxyz = np.matmul(u.T, newxyz2[:][0:newnat].T) # shift for i in range(newnat): outxyz[i, :] = tmpxyz.T[i, :] + oldShift return outxyz tmpxyz = newxyz2[:][0:newnat] # shift for i in range(newnat): outxyz[i, :] = tmpxyz[i, :] + oldShift return outxyz
def exchangeSubstructure( n: int, center: int, subnr: int, bonds: np.ndarray, ref: Molecule, newsub: Molecule, newSubBonds: np.ndarray, name: str, rotate: int, exclude: bool, ): """Exchange substructure (subnr) from ref with substrate.""" # setup initial complex refxyz = ref.get_positions() refat = ref.get_atomic_numbers() refnat = ref.get_number_of_atoms() # match new and old substrate newat = newsub.get_atomic_numbers() newnat = newsub.get_number_of_atoms() # extract coordinates of central atom centralAtom = np.zeros(shape=(1, 3), dtype=np.float64) centralAtom = refxyz[center, :] for i in range(len(bonds[center])): if i == subnr: path = np.zeros(shape=(n, ), dtype=np.int32) # set all elements to -1 path.fill(-1) partner = bonds[center][i] count = Counter() # type: ignore count["step"] = -1 getSubstructures(n, bonds, center, partner, path, count=count) # get rid of -1 elements path = [x for x in path if x != -1] path = np.array(path) # create molecule from given path oldsub = getSubstructureFromPath(ref, path) # get all bonding partner oldSubBonds = oldsub.get_bonds(partner="X") outxyz = np.zeros(shape=(newnat, 3), dtype=np.float64) outxyz = matchSubstrates( bonds, newsub, newSubBonds, oldsub, oldSubBonds, centralAtom, ) # atoms from complex excluding old substrate atoms = [] for i in range(refnat): if i in path: continue atom = Atom(symbol=refat[i], position=refxyz[i, :]) atoms.append(atom) # atoms from new substrate # Should we rotate the substrate around covalent bond? if rotate: theta = rotate origin = refxyz[center, :] partner = outxyz[0, :] outxyz2 = np.zeros(shape=outxyz.shape, dtype=np.float64) # reference shift refShift = getRodriguezRotation(partner, origin, partner, theta) shift = outxyz[0, :] - refShift for i in range(newnat): outxyz2[i, :] = getRodriguezRotation( outxyz[i, :], origin, partner, theta, ) outxyz2[i, :] += shift atom = Atom(symbol=newat[i], position=outxyz2[i, :]) atoms.append(atom) else: for i in range(newnat): atom = Atom(symbol=newat[i], position=outxyz[i, :]) atoms.append(atom) # create molecule from atoms mol = Molecule(symbols=atoms) # write new structure in xyz format mol.writeMolecule(name + ".xyz") # write constrain file refnat = ref.get_number_of_atoms() oldnat = oldsub.get_number_of_atoms() nat = refnat - oldnat writeTransitionMetalConstrains(nat, newnat, newSubBonds, exclude)