def get_linear(species,visited,natom): for j in range(natom): if j not in visited: if species.bond[visited[-1]][j] > 0: if geometry.calc_angle(species.geom[visited[-2]],species.geom[visited[-1]],species.geom[j]) > np.pi * 175. / 180.: visited.append(j) return get_linear(species,visited,natom) if species.bond[visited[0]][j] > 0: if geometry.calc_angle(species.geom[visited[1]],species.geom[visited[0]],species.geom[j]) > np.pi * 175. / 180.: visited.insert(0,j) return get_linear(species,visited,natom) return visited
def get_linear(species, visited, natom): for j in range(natom): if j not in visited: if species.bond[visited[-1]][j] > 0: if geometry.calc_angle(species.geom[visited[-2]], species.geom[visited[-1]], species.geom[j]) > np.pi * 175. / 180.: visited.append(j) return get_linear(species, visited, natom) if species.bond[visited[0]][j] > 0: if geometry.calc_angle(species.geom[visited[1]], species.geom[visited[0]], species.geom[j]) > np.pi * 175. / 180.: visited.insert(0, j) return get_linear(species, visited, natom) return visited
def testCalcAngle(self): """ Test the angle calculation """ # calculate a random anle np.random.seed(1) a = np.random.uniform(size=3) b = np.random.uniform(size=3) c = np.random.uniform(size=3) cal = geometry.calc_angle(a, b, c) exp = 1.24358021797 warn = 'Angle calc faild: exp: {}, calc: {}'.format(exp, cal) self.assertAlmostEqual(exp, cal, places=10, msg=warn) # calculate an angle between to collinear vectors np.random.seed(1) a = np.random.uniform(size=3) b = np.array([0., 0., 0.]) cal = geometry.calc_angle(a, b, a) exp = 0. warn = 'Angle calc faild: exp: {}, calc: {}'.format(exp, cal) self.assertAlmostEqual(exp, cal, places=10, msg=warn) # calculate an angle between to inverse vectors np.random.seed(1) a = np.random.uniform(size=3) b = np.array([0., 0., 0.]) c = -a cal = geometry.calc_angle(a, b, c) exp = np.pi warn = 'Angle calc faild: exp: {}, calc: {}'.format(exp, cal) self.assertAlmostEqual(exp, cal, places=10, msg=warn) # calculate an angle between to orthogonal vectors a = np.array([1., 0., 0.]) b = np.array([0., 0., 0.]) c = np.array([0., 1., 0.]) cal = geometry.calc_angle(a, b, c) exp = np.pi / 2 warn = 'Angle calc faild: exp: {}, calc: {}'.format(exp, cal) self.assertAlmostEqual(exp, cal, places=10, msg=warn)
def add(j,list,zmat,zmat_atom,zmatorder,zmat_ref,atom,cart): """ add an atom on the jth position of the zmat according to the four atoms in the list """ zmat_atom[j] = atom[list[0]] zmatorder[j] = list[0] zmat_ref[j][0] = zmatorder.index(list[1])+1 zmat[j][0] = np.linalg.norm(cart[list[0]] - cart[list[1]]) zmat_ref[j][1] = zmatorder.index(list[2])+1 zmat[j][1] = np.degrees(geometry.calc_angle(cart[list[0]], cart[list[1]], cart[list[2]])) zmat_ref[j][2] = zmatorder.index(list[3])+1 zmat[j][2], collin = geometry.calc_dihedral(cart[list[0]], cart[list[1]], cart[list[2]], cart[list[3]])
def add(j, list, zmat, zmat_atom, zmatorder, zmat_ref, atom, cart): """ add an atom on the jth position of the zmat according to the four atoms in the list """ zmat_atom[j] = atom[list[0]] zmatorder[j] = list[0] zmat_ref[j][0] = zmatorder.index(list[1]) + 1 zmat[j][0] = np.linalg.norm(cart[list[0]] - cart[list[1]]) zmat_ref[j][1] = zmatorder.index(list[2]) + 1 zmat[j][1] = np.degrees(geometry.calc_angle(cart[list[0]], cart[list[1]], cart[list[2]])) zmat_ref[j][2] = zmatorder.index(list[3]) + 1 zmat[j][2], collin = geometry.calc_dihedral(cart[list[0]], cart[list[1]], cart[list[2]], cart[list[3]])
def find_linear(self): self.linear = [] for ati in range(self.natom): for atj in range(self.natom): if self.bonds[0][ati][atj] > 0: for atk in range(self.natom): if self.bonds[0][atj][atk] > 0 and atk != ati: alpha = geometry.calc_angle( self.geom[ati], self.geom[atj], self.geom[atk]) if alpha > 175. * np.pi / 180.: if ati < atk: lin = [ati, atj, atk] else: lin = [atk, atj, ati] if lin not in self.linear: self.linear.append(lin) return
def start_linear(species, natom): """ Get all the 'neighbors' of i which are connected to i via one or a set of linear bonds. This includes * all direct bonds if they are not part of a linear system * all sets of consecutive double bonds * all sets of alternating triple and single bonds Only look at indices larger than i, as the other bonds have been considered with lower indices """ lin = [] for i in range(natom - 1): for j in range(i + 1, natom): if species.bond[i][j] > 0: if len(get_neighbors(species, j)) == 2: k = [ni for ni in get_neighbors(species, j) if ni != i][0] if geometry.calc_angle( species.geom[i], species.geom[j], species.geom[k]) > np.pi * 175. / 180.: new_lin = get_linear(species, [i, j, k], natom) new = 1 for li in lin: if all([ni in li for ni in new_lin]): new = 0 if new: lin.append(new_lin) for i in range(natom - 1): for j in range(i + 1, natom): if species.bond[i][j] > 0: new = 1 for li in lin: if i in li and j in li: new = 0 if new: lin.append([i, j]) return lin
def start_linear(species,natom): """ Get all the 'neighbors' of i which are connected to i via one or a set of linear bonds. This includes * all direct bonds if they are not part of a linear system * all sets of consecutive double bonds * all sets of alternating triple and single bonds Only look at indices larger than i, as the other bonds have been considered with lower indices """ lin = [] for i in range(natom - 1): for j in range(i+1,natom): if species.bond[i][j] > 0: if len(get_neighbors(species,j)) == 2: k = [ni for ni in get_neighbors(species,j) if ni != i][0] if geometry.calc_angle(species.geom[i],species.geom[j],species.geom[k]) > np.pi * 175. / 180.: new_lin = get_linear(species,[i,j,k],natom) new = 1 for li in lin: if all([ni in li for ni in new_lin]): new = 0 if new: lin.append(new_lin) for i in range(natom - 1): for j in range(i+1,natom): if species.bond[i][j] > 0: new = 1 for li in lin: if i in li and j in li: new = 0 if new: lin.append([i,j]) return lin
def control_changes(species, name, geom, new_geom, changes, bond): """ This method controls three things: 1. the changes are all correct 2. the bonded atom pairs that are not part of the changes have the same bond length 3. the non-bonded atom pairs are far enough from each other """ success = 1 gs = '' # initial geomtry string for i, at in enumerate(species.atom): x, y, z = geom[i] gs += '{}, {:.8f}, {:.8f}, {:.8f}, \n'.format(at, x, y, z) cs = '' # changes list for ci in changes: cs += '[{}]\n'.format(', '.join([str(cij) for cij in ci])) # check if the changes are good for ci in changes: if len(ci) == 3: bond_length = np.linalg.norm(new_geom[ci[0]] - new_geom[ci[1]]) if np.abs(bond_length - ci[2]) > 0.05: # use a 0.05 Angstrom cutoff logging.debug("The modified bond length is not correct") logging.debug("Expected {}, got {}".format(ci[2], bond_length)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 if len(ci) == 4: angle = geometry.calc_angle(new_geom[ci[0]], new_geom[ci[1]], new_geom[ci[2]]) change_angle = np.radians(ci[3]) if np.abs(angle - change_angle) > 0.05: # use a 0.05 radians cutoff logging.debug("The modified angle is not correct") logging.debug("Expected {}, got {}".format( change_angle, angle)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 # check if the bond lengths are good: for i in range(species.natom - 1): for j in range(i + 1, species.natom): if bond[i][j] > 0: is_change = 0 for ci in changes: if i in ci and j in ci: is_change = 1 if not is_change: new_bond = np.linalg.norm(new_geom[i] - new_geom[j]) orig_bond = np.linalg.norm(geom[i] - geom[j]) if np.abs(new_bond - orig_bond) > 0.1: # use a 0.1 Angstrom cutoff logging.debug( "The bond length {} {} is not correct after modifications" .format(i, j)) logging.debug("Expected {}, got {}".format( orig_bond, new_bond)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 # check if non-bonded atoms are too close: for i in range(species.natom - 1): for j in range(i + 1, species.natom): if bond[i][j] == 0: dist = np.linalg.norm(new_geom[i] - new_geom[j]) min = constants.st_bond[''.join( sorted([species.atom[i], species.atom[j]]))] if dist < min: logging.debug( "The atoms {} {} are too close after modifications". format(i, j)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 return success
def modify_coordinates(species, name, geom, changes, bond, write_files=0): """ Geom is the geometry (n x 3 matrix with n the number of atoms) in cartesian coordinates Changes is a list of lists, each list containing the coordinates and their new value (atom indices start at 0): To change a bond length: [atom1, atom2, bond_length] To change a bond angle: [neighbor1, central_atom, neighbor2, angle_in_degrees] To change a dihedral angle: [atom1, atom2, atom3, atom4, dihedarl_angle_in_degrees] Bond is the bond matrix of the molecule """ start_time = time.time() logging.debug('Starting coordinate modification for {}'.format(name)) logging.debug('Changes:') for c in changes: logging.debug('\t{}'.format('\t'.join([str(ci) for ci in c]))) step = 1 atoms_list = [] count = 0 fname = '{}_{}.xyz'.format(name, count) while os.path.exists(fname): count += 1 fname = '{}_{}.xyz'.format(name, count) f_out = None if write_files: f_out = open(fname, 'w') new_geom = copy.deepcopy(geom) step = append_geom(species.natom, step, 0., species.atom, new_geom, np.zeros((species.natom * 3)), atoms_list, f_out=f_out) # change dihedrals, if necessary for ci in changes: if len(ci) == 5: zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart( species, ci[:-1], new_geom, 2) # write_zmat(zmat_atom, zmat_ref, zmat, new_geom, species.atom) orig_dih = zmat[3][2] new_dih = ci[-1] dih_diff = new_dih - orig_dih zmat[3][2] += dih_diff for i in range(4, species.natom): if zmat_ref[i][2] == 4: zmat[i][2] += dih_diff if zmat_ref[i][2] == 1: zmat[i][2] += dih_diff new_geom = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref, species.natom, species.atom, zmatorder) # write_zmat(zmat_atom, zmat_ref, zmat, new_geom, species.atom) step = append_geom(species.natom, step, 0., species.atom, new_geom, np.zeros((species.natom * 3)), atoms_list, f_out=f_out) # change angles, if necessary if len(ci) == 4: # original angle in radians orig_angle = geometry.calc_angle(new_geom[ci[0]], new_geom[ci[1]], new_geom[ci[2]]) new_angle = np.radians(ci[-1]) # new angle in radians v1 = new_geom[ci[0]] - new_geom[ci[1]] v2 = new_geom[ci[2]] - new_geom[ci[1]] rot_ax = [0., 0., 0.] # create a vector perpendicular to v1 and v2 # verify if points are collinear if np.linalg.norm(np.cross(v1, v2)) == 0: # rotate around any axis perpendicular to the axis along the three points: if v1[0] != 0 or v1[1] != 0: rot_ax = [v1[1], -v1[0], 0.] elif v1[0] != 0 or v1[2] != 0: rot_ax = [v1[2], 0., -v1[0]] else: rot_ax = [1., 0., 0.] else: rot_ax = np.cross(v1, v2) rot_ax = rot_ax / np.linalg.norm(rot_ax) # rotate all the atoms on the side of the last atom st, ats, ats2 = divide_atoms(ci[2], ci[1], bond, species.natom, species.atom) if not st: break for atj in ats: new_geom[atj] = perform_rotation(new_geom[atj], new_geom[ci[1]], rot_ax, new_angle - orig_angle) step = append_geom(species.natom, step, 1., species.atom, new_geom, np.zeros((species.natom * 3)), atoms_list, f_out=f_out) coords = get_coords(species, bond, new_geom, changes, 0) # optimize the geometry to meet the coords list x0 = np.reshape(new_geom, 3 * species.natom) cost_fct = cost_function(coords) logging.debug('Starting BFGS') gs = '' # initial geomtry string for i, at in enumerate(species.atom): x, y, z = new_geom[i] gs += '{}, {:.8f}, {:.8f}, {:.8f}, \n'.format(at, x, y, z) logging.debug("For the following initial geometry:\n" + gs) opt = bfgs.BFGS() x_opt, x_i, g_i = opt.optimize(cost_fct, x0) new_geom = np.reshape(x_opt, (species.natom, 3)) for i, xi in enumerate(x_i): geomi = np.reshape(xi, (species.natom, 3)) gradi = np.reshape(g_i[i], (species.natom, 3)) step = append_geom(species.natom, step, 2., species.atom, geomi, gradi, atoms_list, f_out=f_out) if write_files: write(fname.replace('.xyz', '.traj'), atoms_list) f_out.close() success = control_changes(species, name, geom, new_geom, changes, bond) end_time = time.time() logging.debug( 'Finished coordinate changes after {:.2f} seconds'.format(end_time - start_time)) return success, new_geom
def make_zmat_from_cart(species, rotor, cart, mode): """ Rearrange geometry defined in Cartesian into a Z-matrix, with references suitable for a 1-D shindered rotor scan. If mode = 0: all rotatable bonds If mode = 1: only those bonds, which generate conformers If mode = 2: suply your one rotor in rotor as a list of atom indices """ natom = species.natom atom = species.atom if mode == 0: a = species.dihed[rotor][0] b = species.dihed[rotor][1] c = species.dihed[rotor][2] d = species.dihed[rotor][3] elif mode == 1: a = species.conf_dihed[rotor][0] b = species.conf_dihed[rotor][1] c = species.conf_dihed[rotor][2] d = species.conf_dihed[rotor][3] elif mode == 2: a = rotor[0] b = rotor[1] c = rotor[2] d = rotor[3] groupA = np.zeros(natom, dtype=int) groupB = np.zeros(natom, dtype=int) groupC = np.zeros(natom, dtype=int) groupD = np.zeros(natom, dtype=int) groupA[a] = 1 groupB[b] = 1 groupC[c] = 1 groupD[d] = 1 #get all immediate neighbors of a A, B, C, and D for i in range(natom): if species.bond[a][i] > 0 and i != b: groupA[i] = 1 elif species.bond[b][i] > 0 and i != a and i != c: groupB[i] = 1 elif species.bond[c][i] > 0 and i != b and i != d: groupC[i] = 1 elif species.bond[d][i] > 0 and i != c: groupD[i] = 1 found = 1 while found > 0: found = 0 for i in range(natom): if groupA[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != b and groupA[j] != 1: groupA[j] = 1 found = 1 elif groupB[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != a and j != c and groupB[j] != 1: groupB[j] = 1 found = 1 elif groupC[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != b and j != d and groupC[j] != 1: groupC[j] = 1 found = 1 elif groupD[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != c and groupD[j] != 1: groupD[j] = 1 found = 1 zmat_atom = ['X' for i in range(natom)] zmat_ref = np.zeros((natom, 3), dtype=int) - 1 zmat = np.zeros((natom, 3)) - 1 # FIXME need to take care about TS strucutres maybe zmatorder = [-1 for i in range(natom)] zmat_atom[0] = atom[a] zmatorder[0] = a zmat_atom[1] = atom[b] zmatorder[1] = b zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[b] - cart[a]) zmat_atom[2] = atom[c] zmatorder[2] = c zmat_ref[2][0] = 2 zmat[2][0] = np.linalg.norm(cart[c] - cart[b]) zmat_ref[2][1] = 1 zmat[2][1] = np.degrees(geometry.calc_angle(cart[c], cart[b], cart[a])) zmat_atom[3] = atom[d] zmatorder[3] = d zmat_ref[3][0] = 3 zmat[3][0] = np.linalg.norm(cart[d] - cart[c]) zmat_ref[3][1] = 2 zmat[3][1] = np.degrees(geometry.calc_angle(cart[d], cart[c], cart[b])) zmat_ref[3][2] = 1 zmat[3][2], collin = geometry.calc_dihedral(cart[d], cart[c], cart[b], cart[a]) j = 4 for i in range(natom): if i == a or i == b or i == c or i == d: continue zmat_atom[j] = atom[i] zmatorder[j] = i if groupA[i] == 1: zmat_ref[j][0] = 1 zmat[j][0] = np.linalg.norm(cart[i] - cart[a]) zmat_ref[j][1] = 2 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[a], cart[b])) zmat_ref[j][2] = 3 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[a], cart[b], cart[c]) elif groupB[i] == 1: zmat_ref[j][0] = 2 zmat[j][0] = np.linalg.norm(cart[i] - cart[b]) zmat_ref[j][1] = 3 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[b], cart[c])) zmat_ref[j][2] = 4 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[b], cart[c], cart[d]) elif groupC[i] == 1: zmat_ref[j][0] = 3 zmat[j][0] = np.linalg.norm(cart[i] - cart[c]) zmat_ref[j][1] = 2 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[c], cart[b])) zmat_ref[j][2] = 1 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[c], cart[b], cart[a]) elif groupD[i] == 1: zmat_ref[j][0] = 4 zmat[j][0] = np.linalg.norm(cart[i] - cart[d]) zmat_ref[j][1] = 3 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[d], cart[c])) zmat_ref[j][2] = 2 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[d], cart[c], cart[b]) j += 1 return zmat_atom, zmat_ref, zmat, zmatorder
def make_zmat_from_cart_all_dihedrals(bond, cycle, dihed, conf_dihed, natom, atom, cart, mode): """ Rearrange geometry defined in Cartesian into a Z-matrix, with references suitable for a 1-D hindered rotor scan. Include all rotors which are: If mode = 0: all rotatable bonds If mode = 1: only those bonds, which generate conformers, i.e. no methyl bonds, t-butyl bonds, etc bond: bond matrix of the species cycle: atom list of species with 0 if atom is not in cycle and 1 otherwise dihed: total list of dihedrals conf_dihed: list of dihedrals without the symmetrical ones natom: number of atoms atom: symbols of all the atoms cart: cartesian coordinates of the species """ rotors = [] #rotors to consider if mode == 0: for rotor in dihed: rotors.append(rotor[:]) if mode == 1: for rotor in conf_dihed: rotors.append(rotor[:]) if len(rotors) > 0: #order in which the atoms will be added: # 1. First rotor # 2. Smallest path between first and second rotor (if any) # 3. Second rotor # 4. Smallest path between second and third rotor (if any) # ... # n. Last rotor # n+1. All atoms that are not part of a rotor, # starting by the neighbors of all rotor atoms #order the rotors as such that the path between subsequent rotors does not #cross another rotor rotors, connecting_list, connected_rotor, path_length = order_rotors(rotors,bond,natom, atom) #Add first rotor: zmat_atom = ['X' for i in range(natom)] zmat_ref = np.zeros((natom, 3), dtype=int) - 1 zmat = np.zeros((natom, 3)) - 1 zmatorder = [-1 for i in range(natom)] zmat_atom[0] = atom[rotors[0][0]] zmatorder[0] = rotors[0][0] zmat_atom[1] = atom[rotors[0][1]] zmatorder[1] = rotors[0][1] zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[rotors[0][1]] - cart[rotors[0][0]]) zmat_atom[2] = atom[rotors[0][2]] zmatorder[2] = rotors[0][2] zmat_ref[2][0] = 2 zmat[2][0] = np.linalg.norm(cart[rotors[0][2]] - cart[rotors[0][1]]) zmat_ref[2][1] = 1 zmat[2][1] = np.degrees(geometry.calc_angle(cart[rotors[0][2]], cart[rotors[0][1]], cart[rotors[0][0]])) zmat_atom[3] = atom[rotors[0][3]] zmatorder[3] = rotors[0][3] zmat_ref[3][0] = 3 zmat[3][0] = np.linalg.norm(cart[rotors[0][3]] - cart[rotors[0][2]]) zmat_ref[3][1] = 2 zmat[3][1] = np.degrees(geometry.calc_angle(cart[rotors[0][3]], cart[rotors[0][2]], cart[rotors[0][1]])) zmat_ref[3][2] = 1 zmat[3][2], collin = geometry.calc_dihedral(cart[rotors[0][3]], cart[rotors[0][2]], cart[rotors[0][1]], cart[rotors[0][0]]) #Add subsequent rotors: rot_index = 1 j = 4 while rot_index < len(rotors): rotor = rotors[rot_index] chain_length = path_length[rot_index - 1] chain = connecting_list[rot_index - 1] conn_rotor = connected_rotor[rot_index - 1] to_add = [] added = [] for at in rotor: if not at in zmatorder: to_add.append(at) else: added.append(at) if len(to_add) == 0: logging.error("error, all atoms of a rotor have been added, without adding this dihedral explicitly") elif len(to_add) == 1: at = to_add[0] if rotor.index(at) == 1 or rotor.index(at) == 2: logging.error("error, all atoms except a middle atom have been added, strange...") elif rotor.index(at) == 0: add(j,[at,rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif rotor.index(at) == 3: add(j,[at,rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif len(to_add) == 2: at1 = to_add[0] at2 = to_add[1] if sorted([rotor.index(at1),rotor.index(at2)]) == [0,1]: neighbor_list = get_neighbors(rotor[2],bond,natom,rotors,zmatorder) #add rotor[1] add(j,[rotor[1],rotor[2],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add rotor[0] add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif sorted([rotor.index(at1),rotor.index(at2)]) == [2,3]: neighbor_list = get_neighbors(rotor[1],bond,natom,rotors,zmatorder) #add rotor[2] add(j,[rotor[2],rotor[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add rotor[3] add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif sorted([rotor.index(at1),rotor.index(at2)]) == [0,3]: r1,pos1 = middle_atom(rotors,rotor[1]) r2,pos2 = middle_atom(rotors,rotor[2]) if r1 and pos1[0] in zmatorder and pos1[1] in zmatorder: #add rotor[0] add(j,[rotor[0],rotor[1],pos1[0],pos1[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add rotor[3] add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif r2 and pos2[0] in zmatorder and pos2[1] in zmatorder: #add rotor[3] add(j,[rotor[3],rotor[2],pos2[0],pos2[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add rotor[0] add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: if cycle[rotor[2]] == 1: neighbor_list = get_neighbors(rotor[2],bond,natom,rotors,zmatorder) #add rotor[3] add(j,[rotor[3],rotor[2],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add rotor[0] add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: neighbor_list = get_neighbors(rotor[1],bond,natom,rotors,zmatorder) #add rotor[0] add(j,[rotor[0],rotor[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add rotor[3] add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif sorted([rotor.index(at1),rotor.index(at2)]) == [0,2]: neighbor_list = get_neighbors(rotor[1],bond,natom,rotors,zmatorder) #add rotor[2] add(j,[rotor[2],rotor[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) #add rotor[0] add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif sorted([rotor.index(at1),rotor.index(at2)]) == [1,3]: neighbor_list = get_neighbors(rotor[0],bond,natom,rotors,zmatorder) #add rotor[1] add(j,[rotor[1],rotor[0],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) #add rotor[3] add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: logging.error("error, two atoms that need to be added are not the outer atoms of a rotor, strange...") elif len(to_add) == 3: if added[0] == rotor[0]: neighbor_list = get_neighbors(rotor[0],bond,natom,rotors,zmatorder) add(j,[rotor[1],rotor[0],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],rotor[0],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif added[0] == rotor[1]: neighbor_list = get_neighbors(rotor[1],bond,natom,rotors,zmatorder) if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j,[rotor[2],rotor[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: add(j,[rotor[0],rotor[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif added[0] == rotor[2]: neighbor_list = get_neighbors(rotor[2],bond,natom,rotors,zmatorder) if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j,[rotor[3],rotor[2],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: add(j,[rotor[1],rotor[2],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif added[0] == rotor[3]: neighbor_list = get_neighbors(rotor[3],bond,natom,rotors,zmatorder) add(j,[rotor[2],rotor[3],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],rotor[3],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: logging.error('error') else: if len(chain) == 2: #this is the minimum chain length neighbor_list=get_neighbors(chain[1],bond,natom,rotors,zmatorder) if chain[0] == rotor[0]: add(j,[rotor[0],chain[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[0],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],rotor[0],chain[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif chain[0] == rotor[1]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j,[rotor[1],chain[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],chain[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: add(j,[rotor[1],chain[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif chain[0] == rotor[2]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j,[rotor[2],chain[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: add(j,[rotor[2],chain[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],chain[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif chain[0] == rotor[3]: add(j,[rotor[3],chain[1],neighbor_list[0],neighbor_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[3],chain[1],neighbor_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],rotor[3],chain[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif len(chain) > 2: neighbor_list=get_neighbors(chain[-1],bond,natom,rotors,zmatorder) #add the chain of atoms between this rotor and the closest rotor that is already in the zmatrix for i in range(1,len(chain)-1): #do not consider two outer atoms, which are part of a rotor ref_list = [] if i == 1: ref_list = [chain[-1],neighbor_list[0],neighbor_list[1]] elif i == 2: ref_list = [chain[-2],chain[-1],neighbor_list[0]] else: ref_list = [chain[-i],chain[-(i-1)],chain[-(i-2)]] add(j,[chain[-(i+1)],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 #add the rotor itself: ref_list = [] if len(chain) == 3: #only one atom connects the two rotors: ref_list = [chain[1],chain[2],neighbor_list[0]] else: ref_list = [chain[1],chain[2],chain[3]] if chain[0] == rotor[0]: add(j,[rotor[0],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[0],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],rotor[0],ref_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif chain[0] == rotor[1]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j,[rotor[1],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],ref_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: add(j,[rotor[1],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[1],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif chain[0] == rotor[2]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j,[rotor[2],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: add(j,[rotor[2],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],ref_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[3],rotor[2],rotor[1],rotor[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 elif chain[0] == rotor[3]: add(j,[rotor[3],ref_list[0],ref_list[1],ref_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[2],rotor[3],ref_list[0],ref_list[1]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[1],rotor[2],rotor[3],ref_list[0]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 add(j,[rotor[0],rotor[1],rotor[2],rotor[3]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 else: logging.error('error, chain length too small') rot_index += 1 else: # no rotors here, add the first four atoms of the molecule zmat_atom = ['X' for i in range(natom)] zmat_ref = np.zeros((natom, 3), dtype=int) - 1 zmat = np.zeros((natom, 3)) - 1 zmatorder = [-1 for i in range(natom)] if len(atom) == 1: zmat_atom[0] = atom[0] zmatorder[0] = 0 elif len(atom) == 2: zmat_atom[0] = atom[0] zmatorder[0] = 0 zmat_atom[1] = atom[1] zmatorder[1] = 1 zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[1] - cart[0]) else: # get three atoms that are bonded to one another motif = ['X','X','X'] ins = start_motif(motif, natom, bond, atom, -1, [[k] for k in range(natom)])[0] zmat_atom[0] = atom[ins[0]] zmatorder[0] = ins[0] zmat_atom[1] = atom[ins[1]] zmatorder[1] = ins[1] zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[ins[1]] - cart[ins[0]]) zmat_atom[2] = atom[ins[2]] zmatorder[2] = ins[2] zmat_ref[2][0] = 2 zmat[2][0] = np.linalg.norm(cart[ins[2]] - cart[ins[1]]) zmat_ref[2][1] = 1 zmat[2][1] = np.degrees(geometry.calc_angle(cart[ins[2]], cart[ins[1]], cart[ins[0]])) j = 3 #add all the remaining atoms while -1 in zmatorder: for i in range(natom): if not i in zmatorder: neighbor_list = get_three_neighbors(i,bond,natom,rotors,zmatorder) if len(neighbor_list) > 2: add(j,[i,neighbor_list[0],neighbor_list[1],neighbor_list[2]],zmat,zmat_atom,zmatorder,zmat_ref,atom,cart) j += 1 return zmat_atom, zmat_ref, zmat, zmatorder
def make_zmat_from_cart(species, rotor, cart, mode): """ Rearrange geometry defined in Cartesian into a Z-matrix, with references suitable for a 1-D hindered rotor scan. If mode = 0: all rotatable bonds If mode = 1: only those bonds, which generate conformers If mode = 2: suply your one rotor in rotor as a list of atom indices """ natom = species.natom atom = species.atom if mode == 0: a = species.dihed[rotor][0] b = species.dihed[rotor][1] c = species.dihed[rotor][2] d = species.dihed[rotor][3] elif mode == 1: a = species.conf_dihed[rotor][0] b = species.conf_dihed[rotor][1] c = species.conf_dihed[rotor][2] d = species.conf_dihed[rotor][3] elif mode == 2: a = rotor[0] b = rotor[1] c = rotor[2] d = rotor[3] groupA = np.zeros(natom, dtype=int) groupB = np.zeros(natom, dtype=int) groupC = np.zeros(natom, dtype=int) groupD = np.zeros(natom, dtype=int) groupA[a] = 1 groupB[b] = 1 groupC[c] = 1 groupD[d] = 1 # get all immediate neighbors of a A, B, C, and D for i in range(natom): if species.bond[a][i] > 0 and i != b: groupA[i] = 1 elif species.bond[b][i] > 0 and i != a and i != c: groupB[i] = 1 elif species.bond[c][i] > 0 and i != b and i != d: groupC[i] = 1 elif species.bond[d][i] > 0 and i != c: groupD[i] = 1 found = 1 while found > 0: found = 0 for i in range(natom): if groupA[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != b and groupA[j] != 1: groupA[j] = 1 found = 1 elif groupB[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != a and j != c and groupB[j] != 1: groupB[j] = 1 found = 1 elif groupC[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != b and j != d and groupC[j] != 1: groupC[j] = 1 found = 1 elif groupD[i] == 1: for j in range(natom): if species.bond[i][j] > 0 and j != c and groupD[j] != 1: groupD[j] = 1 found = 1 zmat_atom = ['X' for i in range(natom)] zmat_ref = np.zeros((natom, 3), dtype=int) - 1 zmat = np.zeros((natom, 3)) - 1 # FIXME need to take care about TS structures maybe zmatorder = [-1 for i in range(natom)] zmat_atom[0] = atom[a] zmatorder[0] = a zmat_atom[1] = atom[b] zmatorder[1] = b zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[b] - cart[a]) zmat_atom[2] = atom[c] zmatorder[2] = c zmat_ref[2][0] = 2 zmat[2][0] = np.linalg.norm(cart[c] - cart[b]) zmat_ref[2][1] = 1 zmat[2][1] = np.degrees(geometry.calc_angle(cart[c], cart[b], cart[a])) zmat_atom[3] = atom[d] zmatorder[3] = d zmat_ref[3][0] = 3 zmat[3][0] = np.linalg.norm(cart[d] - cart[c]) zmat_ref[3][1] = 2 zmat[3][1] = np.degrees(geometry.calc_angle(cart[d], cart[c], cart[b])) zmat_ref[3][2] = 1 zmat[3][2], collin = geometry.calc_dihedral(cart[d], cart[c], cart[b], cart[a]) j = 4 for i in range(natom): if i == a or i == b or i == c or i == d: continue zmat_atom[j] = atom[i] zmatorder[j] = i if groupA[i] == 1: zmat_ref[j][0] = 1 zmat[j][0] = np.linalg.norm(cart[i] - cart[a]) zmat_ref[j][1] = 2 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[a], cart[b])) zmat_ref[j][2] = 3 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[a], cart[b], cart[c]) elif groupB[i] == 1: zmat_ref[j][0] = 2 zmat[j][0] = np.linalg.norm(cart[i] - cart[b]) zmat_ref[j][1] = 3 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[b], cart[c])) zmat_ref[j][2] = 4 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[b], cart[c], cart[d]) elif groupC[i] == 1: zmat_ref[j][0] = 3 zmat[j][0] = np.linalg.norm(cart[i] - cart[c]) zmat_ref[j][1] = 2 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[c], cart[b])) zmat_ref[j][2] = 1 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[c], cart[b], cart[a]) elif groupD[i] == 1: zmat_ref[j][0] = 4 zmat[j][0] = np.linalg.norm(cart[i] - cart[d]) zmat_ref[j][1] = 3 zmat[j][1] = np.degrees(geometry.calc_angle(cart[i], cart[d], cart[c])) zmat_ref[j][2] = 2 zmat[j][2], collin = geometry.calc_dihedral(cart[i], cart[d], cart[c], cart[b]) j += 1 return zmat_atom, zmat_ref, zmat, zmatorder
def make_zmat_from_cart_all_dihedrals(bond, cycle, dihed, conf_dihed, natom, atom, cart, mode): """ Rearrange geometry defined in Cartesian into a Z-matrix, with references suitable for a 1-D hindered rotor scan. Include all rotors which are: If mode = 0: all rotatable bonds If mode = 1: only those bonds, which generate conformers, i.e. no methyl bonds, t-butyl bonds, etc bond: bond matrix of the species cycle: atom list of species with 0 if atom is not in cycle and 1 otherwise dihed: total list of dihedrals conf_dihed: list of dihedrals without the symmetrical ones natom: number of atoms atom: symbols of all the atoms cart: cartesian coordinates of the species """ rotors = [] # rotors to consider if mode == 0: for rotor in dihed: rotors.append(rotor[:]) if mode == 1: for rotor in conf_dihed: rotors.append(rotor[:]) if len(rotors) > 0: # order in which the atoms will be added: # 1. First rotor # 2. Smallest path between first and second rotor (if any) # 3. Second rotor # 4. Smallest path between second and third rotor (if any) # ... # n. Last rotor # n+1. All atoms that are not part of a rotor, # starting by the neighbors of all rotor atoms # order the rotors as such that the path between subsequent rotors does not # cross another rotor rotors, connecting_list, connected_rotor, path_length = order_rotors(rotors, bond, natom, atom) # Add first rotor: zmat_atom = ['X' for i in range(natom)] zmat_ref = np.zeros((natom, 3), dtype=int) - 1 zmat = np.zeros((natom, 3)) - 1 zmatorder = [-1 for i in range(natom)] zmat_atom[0] = atom[rotors[0][0]] zmatorder[0] = rotors[0][0] zmat_atom[1] = atom[rotors[0][1]] zmatorder[1] = rotors[0][1] zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[rotors[0][1]] - cart[rotors[0][0]]) zmat_atom[2] = atom[rotors[0][2]] zmatorder[2] = rotors[0][2] zmat_ref[2][0] = 2 zmat[2][0] = np.linalg.norm(cart[rotors[0][2]] - cart[rotors[0][1]]) zmat_ref[2][1] = 1 zmat[2][1] = np.degrees(geometry.calc_angle(cart[rotors[0][2]], cart[rotors[0][1]], cart[rotors[0][0]])) zmat_atom[3] = atom[rotors[0][3]] zmatorder[3] = rotors[0][3] zmat_ref[3][0] = 3 zmat[3][0] = np.linalg.norm(cart[rotors[0][3]] - cart[rotors[0][2]]) zmat_ref[3][1] = 2 zmat[3][1] = np.degrees(geometry.calc_angle(cart[rotors[0][3]], cart[rotors[0][2]], cart[rotors[0][1]])) zmat_ref[3][2] = 1 zmat[3][2], collin = geometry.calc_dihedral(cart[rotors[0][3]], cart[rotors[0][2]], cart[rotors[0][1]], cart[rotors[0][0]]) # Add subsequent rotors: rot_index = 1 j = 4 while rot_index < len(rotors): rotor = rotors[rot_index] chain_length = path_length[rot_index - 1] chain = connecting_list[rot_index - 1] conn_rotor = connected_rotor[rot_index - 1] to_add = [] added = [] for at in rotor: if at not in zmatorder: to_add.append(at) else: added.append(at) if len(to_add) == 0: logging.error("error, all atoms of a rotor have been added, without adding this dihedral explicitly") elif len(to_add) == 1: at = to_add[0] if rotor.index(at) == 1 or rotor.index(at) == 2: logging.error("error, all atoms except a middle atom have been added, strange...") elif rotor.index(at) == 0: add(j, [at, rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif rotor.index(at) == 3: add(j, [at, rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif len(to_add) == 2: at1 = to_add[0] at2 = to_add[1] if sorted([rotor.index(at1), rotor.index(at2)]) == [0, 1]: neighbor_list = get_neighbors(rotor[2], bond, natom, rotors, zmatorder) # add rotor[1] add(j, [rotor[1], rotor[2], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add rotor[0] add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif sorted([rotor.index(at1), rotor.index(at2)]) == [2, 3]: neighbor_list = get_neighbors(rotor[1], bond, natom, rotors, zmatorder) # add rotor[2] add(j, [rotor[2], rotor[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add rotor[3] add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif sorted([rotor.index(at1), rotor.index(at2)]) == [0, 3]: r1, pos1 = middle_atom(rotors, rotor[1]) r2, pos2 = middle_atom(rotors, rotor[2]) if r1 and pos1[0] in zmatorder and pos1[1] in zmatorder: # add rotor[0] add(j, [rotor[0], rotor[1], pos1[0], pos1[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add rotor[3] add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif r2 and pos2[0] in zmatorder and pos2[1] in zmatorder: # add rotor[3] add(j, [rotor[3], rotor[2], pos2[0], pos2[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add rotor[0] add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: if cycle[rotor[2]] == 1: neighbor_list = get_neighbors(rotor[2], bond, natom, rotors, zmatorder) # add rotor[3] add(j, [rotor[3], rotor[2], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add rotor[0] add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: neighbor_list = get_neighbors(rotor[1], bond, natom, rotors, zmatorder) # add rotor[0] add(j, [rotor[0], rotor[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add rotor[3] add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif sorted([rotor.index(at1), rotor.index(at2)]) == [0, 2]: neighbor_list = get_neighbors(rotor[1], bond, natom, rotors, zmatorder) # add rotor[2] add(j, [rotor[2], rotor[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) # add rotor[0] add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif sorted([rotor.index(at1), rotor.index(at2)]) == [1, 3]: neighbor_list = get_neighbors(rotor[0], bond, natom, rotors, zmatorder) # add rotor[1] add(j, [rotor[1], rotor[0], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) # add rotor[3] add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: logging.error("error, two atoms that need to be added are not the outer atoms of a rotor, strange...") elif len(to_add) == 3: if added[0] == rotor[0]: neighbor_list = get_neighbors(rotor[0], bond, natom, rotors, zmatorder) add(j, [rotor[1], rotor[0], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], rotor[0], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif added[0] == rotor[1]: neighbor_list = get_neighbors(rotor[1], bond, natom, rotors, zmatorder) if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j, [rotor[2], rotor[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: add(j, [rotor[0], rotor[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif added[0] == rotor[2]: neighbor_list = get_neighbors(rotor[2], bond, natom, rotors, zmatorder) if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j, [rotor[3], rotor[2], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: add(j, [rotor[1], rotor[2], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif added[0] == rotor[3]: neighbor_list = get_neighbors(rotor[3], bond, natom, rotors, zmatorder) add(j, [rotor[2], rotor[3], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], rotor[3], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: logging.error('error') else: if len(chain) == 2: # this is the minimum chain length neighbor_list = get_neighbors(chain[1], bond, natom, rotors, zmatorder) if chain[0] == rotor[0]: add(j, [rotor[0], chain[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[0], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], rotor[0], chain[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif chain[0] == rotor[1]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j, [rotor[1], chain[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], chain[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: add(j, [rotor[1], chain[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif chain[0] == rotor[2]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j, [rotor[2], chain[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: add(j, [rotor[2], chain[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], chain[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif chain[0] == rotor[3]: add(j, [rotor[3], chain[1], neighbor_list[0], neighbor_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[3], chain[1], neighbor_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], rotor[3], chain[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif len(chain) > 2: neighbor_list = get_neighbors(chain[-1], bond, natom, rotors, zmatorder) # add the chain of atoms between this rotor and the closest rotor that is already in the zmatrix for i in range(1, len(chain) - 1): # do not consider two outer atoms, which are part of a rotor ref_list = [] if i == 1: ref_list = [chain[-1], neighbor_list[0], neighbor_list[1]] elif i == 2: ref_list = [chain[-2], chain[-1], neighbor_list[0]] else: ref_list = [chain[-i], chain[-(i - 1)], chain[-(i - 2)]] add(j, [chain[-(i + 1)], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 # add the rotor itself: ref_list = [] if len(chain) == 3: # only one atom connects the two rotors: ref_list = [chain[1], chain[2], neighbor_list[0]] else: ref_list = [chain[1], chain[2], chain[3]] if chain[0] == rotor[0]: add(j, [rotor[0], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[0], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], rotor[0], ref_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif chain[0] == rotor[1]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j, [rotor[1], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], ref_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: add(j, [rotor[1], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[1], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif chain[0] == rotor[2]: if cycle[rotor[3]] == 1 or cycle[rotor[2]] == 1: add(j, [rotor[2], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: add(j, [rotor[2], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], ref_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[3], rotor[2], rotor[1], rotor[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 elif chain[0] == rotor[3]: add(j, [rotor[3], ref_list[0], ref_list[1], ref_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[2], rotor[3], ref_list[0], ref_list[1]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[1], rotor[2], rotor[3], ref_list[0]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 add(j, [rotor[0], rotor[1], rotor[2], rotor[3]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 else: logging.error('error, chain length too small') rot_index += 1 else: # no rotors here, add the first four atoms of the molecule zmat_atom = ['X' for i in range(natom)] zmat_ref = np.zeros((natom, 3), dtype=int) - 1 zmat = np.zeros((natom, 3)) - 1 zmatorder = [-1 for i in range(natom)] if len(atom) == 1: zmat_atom[0] = atom[0] zmatorder[0] = 0 elif len(atom) == 2: zmat_atom[0] = atom[0] zmatorder[0] = 0 zmat_atom[1] = atom[1] zmatorder[1] = 1 zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[1] - cart[0]) else: # get three atoms that are bonded to one another motif = ['X', 'X', 'X'] ins = start_motif(motif, natom, bond, atom, -1, [[k] for k in range(natom)])[0] zmat_atom[0] = atom[ins[0]] zmatorder[0] = ins[0] zmat_atom[1] = atom[ins[1]] zmatorder[1] = ins[1] zmat_ref[1][0] = 1 zmat[1][0] = np.linalg.norm(cart[ins[1]] - cart[ins[0]]) zmat_atom[2] = atom[ins[2]] zmatorder[2] = ins[2] zmat_ref[2][0] = 2 zmat[2][0] = np.linalg.norm(cart[ins[2]] - cart[ins[1]]) zmat_ref[2][1] = 1 zmat[2][1] = np.degrees(geometry.calc_angle(cart[ins[2]], cart[ins[1]], cart[ins[0]])) j = 3 # add all the remaining atoms while -1 in zmatorder: for i in range(natom): if i not in zmatorder: neighbor_list = get_three_neighbors(i, bond, natom, rotors, zmatorder) if len(neighbor_list) > 2: add(j, [i, neighbor_list[0], neighbor_list[1], neighbor_list[2]], zmat, zmat_atom, zmatorder, zmat_ref, atom, cart) j += 1 return zmat_atom, zmat_ref, zmat, zmatorder
def control_changes(species, name, geom, new_geom, changes, bond): """ This method controls three things: 1. the changes are all correct 2. the bonded atom pairs that are not part of the changes have the same bond length 3. the non-bonded atom pairs are far enough from each other """ success = 1 gs = '' # initial geomtry string for i, at in enumerate(species.atom): x, y, z = geom[i] gs += '{}, {:.8f}, {:.8f}, {:.8f}, \n'.format(at, x, y, z) cs = '' # changes list for ci in changes: cs += '[{}]\n'.format(', '.join([str(cij) for cij in ci])) # check if the changes are good for ci in changes: if len(ci) == 3: bond_length = np.linalg.norm(new_geom[ci[0]] - new_geom[ci[1]]) if np.abs(bond_length - ci[2]) > 0.05: # use a 0.05 Angstrom cutoff logging.debug("The modified bond length is not correct") logging.debug("Expected {}, got {}".format(ci[2], bond_length)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 if len(ci) == 4: angle = geometry.calc_angle(new_geom[ci[0]], new_geom[ci[1]], new_geom[ci[2]]) change_angle = np.radians(ci[3]) if np.abs(angle - change_angle) > 0.05: # use a 0.05 radians cutoff logging.debug("The modified angle is not correct") logging.debug("Expected {}, got {}".format(change_angle, angle)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 # check if the bond lengths are good: for i in range(species.natom - 1): for j in range(i+1, species.natom): if bond[i][j] > 0: is_change = 0 for ci in changes: if i in ci and j in ci: is_change = 1 if not is_change: new_bond = np.linalg.norm(new_geom[i] - new_geom[j]) orig_bond = np.linalg.norm(geom[i] - geom[j]) if np.abs(new_bond - orig_bond) > 0.1: # use a 0.1 Angstrom cutoff logging.debug("The bond length {} {} is not correct after modifications".format(i, j)) logging.debug("Expected {}, got {}".format(orig_bond, new_bond)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 # check if non-bonded atoms are too close: for i in range(species.natom - 1): for j in range(i+1, species.natom): if bond[i][j] == 0: dist = np.linalg.norm(new_geom[i] - new_geom[j]) min = constants.st_bond[''.join(sorted([species.atom[i], species.atom[j]]))] if dist < min: logging.debug("The atoms {} {} are too close after modifications".format(i, j)) logging.debug("Species name: " + name) logging.debug("For the following initial geometry:\n" + gs) logging.debug("And the following change list:\n" + cs) success = 0 return success
def modify_coordinates(species, name, geom, changes, bond, write_files=0): """ Geom is the geometry (n x 3 matrix with n the number of atoms) in cartesian coordinates Changes is a list of lists, each list containing the coordinates and their new value (atom indices start at 0): To change a bond length: [atom1, atom2, bond_length] To change a bond angle: [neighbor1, central_atom, neighbor2, angle_in_degrees] To change a dihedral angle: [atom1, atom2, atom3, atom4, dihedarl_angle_in_degrees] Bond is the bond matrix of the molecule """ start_time = time.time() logging.debug('Starting coordinate modification for {}'.format(name)) logging.debug('Changes:') for c in changes: logging.debug('\t{}'.format('\t'.join([str(ci) for ci in c]))) step = 1 atoms_list = [] count = 0 fname = '{}_{}.xyz'.format(name, count) while os.path.exists(fname): count += 1 fname = '{}_{}.xyz'.format(name, count) f_out = None if write_files: f_out = open(fname, 'w') new_geom = copy.deepcopy(geom) step = append_geom(species.natom, step, 0., species.atom, new_geom, np.zeros((species.natom*3)), atoms_list, f_out=f_out) # change dihedrals, if necessary for ci in changes: if len(ci) == 5: zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(species, ci[:-1], new_geom, 2) # write_zmat(zmat_atom, zmat_ref, zmat, new_geom, species.atom) orig_dih = zmat[3][2] new_dih = ci[-1] dih_diff = new_dih - orig_dih zmat[3][2] += dih_diff for i in range(4, species.natom): if zmat_ref[i][2] == 4: zmat[i][2] += dih_diff if zmat_ref[i][2] == 1: zmat[i][2] += dih_diff new_geom = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref, species.natom, species.atom, zmatorder) # write_zmat(zmat_atom, zmat_ref, zmat, new_geom, species.atom) step = append_geom(species.natom, step, 0., species.atom, new_geom, np.zeros((species.natom*3)), atoms_list, f_out=f_out) # change angles, if necessary if len(ci) == 4: # original angle in radians orig_angle = geometry.calc_angle(new_geom[ci[0]], new_geom[ci[1]], new_geom[ci[2]]) new_angle = np.radians(ci[-1]) # new angle in radians v1 = new_geom[ci[0]] - new_geom[ci[1]] v2 = new_geom[ci[2]] - new_geom[ci[1]] rot_ax = [0., 0., 0.] # create a vector perpendicular to v1 and v2 # verify if points are collinear if np.linalg.norm(np.cross(v1, v2)) == 0: # rotate around any axis perpendicular to the axis along the three points: if v1[0] != 0 or v1[1] != 0: rot_ax = [v1[1], -v1[0], 0.] elif v1[0] != 0 or v1[2] != 0: rot_ax = [v1[2], 0., -v1[0]] else: rot_ax = [1., 0., 0.] else: rot_ax = np.cross(v1, v2) rot_ax = rot_ax/np.linalg.norm(rot_ax) # rotate all the atoms on the side of the last atom st, ats, ats2 = divide_atoms(ci[2], ci[1], bond, species.natom, species.atom) if not st: break for atj in ats: new_geom[atj] = perform_rotation(new_geom[atj], new_geom[ci[1]], rot_ax, new_angle-orig_angle) step = append_geom(species.natom, step, 1., species.atom, new_geom, np.zeros((species.natom*3)), atoms_list, f_out=f_out) coords = get_coords(species, bond, new_geom, changes, 0) # optimize the geometry to meet the coords list x0 = np.reshape(new_geom, 3*species.natom) cost_fct = cost_function(coords) logging.debug('Starting BFGS') gs = '' # initial geomtry string for i, at in enumerate(species.atom): x, y, z = new_geom[i] gs += '{}, {:.8f}, {:.8f}, {:.8f}, \n'.format(at, x, y, z) logging.debug("For the following initial geometry:\n" + gs) opt = bfgs.BFGS() x_opt, x_i, g_i = opt.optimize(cost_fct, x0) new_geom = np.reshape(x_opt, (species.natom, 3)) for i, xi in enumerate(x_i): geomi = np.reshape(xi, (species.natom, 3)) gradi = np.reshape(g_i[i], (species.natom, 3)) step = append_geom(species.natom, step, 2., species.atom, geomi, gradi, atoms_list, f_out=f_out) if write_files: write(fname.replace('.xyz', '.traj'), atoms_list) f_out.close() success = control_changes(species, name, geom, new_geom, changes, bond) end_time = time.time() logging.debug('Finished coordinate changes after {:.2f} seconds'.format(end_time - start_time)) return success, new_geom