Пример #1
0
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
Пример #2
0
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
Пример #3
0
    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)
Пример #4
0
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]])
Пример #5
0
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]])
Пример #6
0
    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
Пример #7
0
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
Пример #8
0
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
Пример #9
0
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
Пример #10
0
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
Пример #11
0
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
Пример #12
0
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
Пример #13
0
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
Пример #14
0
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
Пример #15
0
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
Пример #16
0
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