示例#1
0
    def generate_conformers_random_sampling(self, ini_cart):
        """
        Generate a random sampling of each dihedral for a number nconfs of conformers
        """
        for ni in range(self.nconfs):
            cart = copy.deepcopy(ini_cart)
            if ni == 0:
                sample = [0. for di in self.species.conf_dihed]
            else:
                sample = [
                    random.choice([0., 120., 240.])
                    for di in self.species.conf_dihed
                ]
            for rotor in range(len(self.species.conf_dihed)):
                zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(
                    self.species, rotor, cart, 1)
                zmat[3][2] += sample[rotor]
                for i in range(4, self.species.natom):
                    if zmat_ref[i][2] == 4:
                        zmat[i][2] += sample[rotor]
                    if zmat_ref[i][2] == 1:
                        zmat[i][2] += sample[rotor]
                cart = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref,
                                                   self.species.natom,
                                                   self.species.atom,
                                                   zmatorder)
            self.qc.qc_conf(self.species, cart, self.conf)
            self.conf += 1

        return 0
示例#2
0
    def generate_conformers(self, rotor, cart):
        """
        Generate guesses for all of the canonical conformers.
        This is a recursive routine to generate them.
        rotor: the rotor number in the order it was discovered
        """

        if self.cyc_conf == 0:
            cycles = 1
        else:
            cycles = self.cyc_conf

        theoretical_confs = np.power(3, len(self.species.conf_dihed)) * cycles
        if len(self.species.conf_dihed
               ) > self.max_dihed or theoretical_confs > self.nconfs:
            self.generate_conformers_random_sampling(cart)
            return 0

        if rotor == len(self.species.conf_dihed):
            self.qc.qc_conf(self.species, cart, self.conf)
            self.conf += 1
            return 0

        cart = np.asarray(cart)
        zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(
            self.species, rotor, cart, 1)

        rotor += 1
        cart0 = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref,
                                            self.species.natom,
                                            self.species.atom, zmatorder)
        self.generate_conformers(rotor, cart0)

        zmat[3][2] += 120.
        for i in range(4, self.species.natom):
            if zmat_ref[i][2] == 4:
                zmat[i][2] += 120.
            if zmat_ref[i][2] == 1:
                zmat[i][2] += 120.
        cart1 = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref,
                                            self.species.natom,
                                            self.species.atom, zmatorder)
        self.generate_conformers(rotor, cart1)

        zmat[3][2] += 120.
        for i in range(4, self.species.natom):
            if zmat_ref[i][2] == 4:
                zmat[i][2] += 120.
            if zmat_ref[i][2] == 1:
                zmat[i][2] += 120.
        cart2 = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref,
                                            self.species.natom,
                                            self.species.atom, zmatorder)
        self.generate_conformers(rotor, cart2)

        return 0
示例#3
0
    def generate_hir_geoms(self, cart, rigid):
        """
        Generate the initial geometries of the points along the scans
        """
        # re-initialize the lists in case of a restart of the HIR scans
        self.hir_status = []
        self.hir_energies = []
        self.hir_geoms = []

        while len(self.hir_status) < len(self.species.dihed):
            self.hir_status.append([-1 for i in range(self.nrotation)])
            self.hir_energies.append([-1 for i in range(self.nrotation)])
            self.hir_geoms.append([[] for i in range(self.nrotation)])

        for rotor in range(len(self.species.dihed)):
            if skip_rotor(self.species.name, self.species.dihed[rotor]) == 1:
                self.hir_status[rotor] = [2 for i in range(self.nrotation)]
                logging.info('For {} rotor {} was skipped in HIR.'.format(
                    self.species.name, rotor))
                continue

            cart = np.asarray(cart)
            zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(
                self.species, rotor, cart, 0)

            # first element has same geometry
            # ( TODO: this shouldn't be recalculated)
            cart_new = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref,
                                                   self.species.natom,
                                                   self.species.atom,
                                                   zmatorder)
            fi = [(zi + 1) for zi in zmatorder[:4]]
            self.qc.qc_hir(self.species, cart_new, rotor, 0, [fi], rigid)
            for ai in range(1, self.nrotation):
                ang = 360. / float(self.nrotation)
                zmat[3][2] += ang
                for i in range(4, self.species.natom):
                    if zmat_ref[i][2] == 4:
                        zmat[i][2] += ang
                    if zmat_ref[i][2] == 1:
                        zmat[i][2] += ang
                cart_new = zmatrix.make_cart_from_zmat(zmat, zmat_atom,
                                                       zmat_ref,
                                                       self.species.natom,
                                                       self.species.atom,
                                                       zmatorder)
                self.qc.qc_hir(self.species, cart_new, rotor, ai, [fi], rigid)
        return 0
示例#4
0
    def generate_hir_geoms(self, cart):
        """
        Generate the initial geometries of the points along the scans
        """
        # re-initialize the lists incase of a restart of the HIR scans
        self.hir_status = []
        self.hir_energies = []
        self.hir_geoms = []

        while len(self.hir_status) < len(self.species.dihed):
            self.hir_status.append([-1 for i in range(self.nrotation)])
            self.hir_energies.append([-1 for i in range(self.nrotation)])
            self.hir_geoms.append([[] for i in range(self.nrotation)])

        for rotor in range(len(self.species.dihed)):
            cart = np.asarray(cart)
            zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(self.species, rotor, cart, 0)

            # first element has same geometry
            # ( TODO: this shouldn't be recalculated)
            cart_new = zmatrix.make_cart_from_zmat(zmat,
                                                   zmat_atom,
                                                   zmat_ref,
                                                   self.species.natom,
                                                   self.species.atom,
                                                   zmatorder)
            fi = [(zi+1) for zi in zmatorder[:4]]
            self.qc.qc_hir(self.species, cart_new, rotor, 0, [fi])
            for ai in range(1, self.nrotation):
                ang = 360. / float(self.nrotation)
                zmat[3][2] += ang
                for i in range(4, self.species.natom):
                    if zmat_ref[i][2] == 4:
                        zmat[i][2] += ang
                    if zmat_ref[i][2] == 1:
                        zmat[i][2] += ang
                cart_new = zmatrix.make_cart_from_zmat(zmat,
                                                       zmat_atom,
                                                       zmat_ref,
                                                       self.species.natom,
                                                       self.species.atom,
                                                       zmatorder)
                self.qc.qc_hir(self.species, cart_new, rotor, ai, [fi])
        return 0
示例#5
0
    def generate_conformers(self, rotor, cart):
        """
        Generate guesses for all of the canonical conformers.
        This is a recursive routine to generate them.
        rotor: the rotor number in the order it was discovered
        """
        if len(self.species.conf_dihed) > self.max_dihed:
            self.generate_conformers_random_sampling(cart)
            return 0

        if rotor == len(self.species.conf_dihed):
            self.qc.qc_conf(self.species, cart, self.conf)
            self.conf += 1
            return 0

        cart = np.asarray(cart)
        zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(self.species, rotor, cart, 1)

        rotor += 1
        cart0 = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref, self.species.natom, self.species.atom, zmatorder)
        self.generate_conformers(rotor, cart0)

        zmat[3][2] += 120.
        for i in range(4, self.species.natom):
            if zmat_ref[i][2] == 4:
                zmat[i][2] += 120.
            if zmat_ref[i][2] == 1:
                zmat[i][2] += 120.
        cart1 = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref, self.species.natom, self.species.atom, zmatorder)
        self.generate_conformers(rotor, cart1)

        zmat[3][2] += 120.
        for i in range(4, self.species.natom):
            if zmat_ref[i][2] == 4:
                zmat[i][2] += 120.
            if zmat_ref[i][2] == 1:
                zmat[i][2] += 120.
        cart2 = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref, self.species.natom, self.species.atom, zmatorder)
        self.generate_conformers(rotor, cart2)

        return 0
示例#6
0
    def generate_conformers_random_sampling(self, ini_cart):
        """
        Generate a random sampling of each dihedral for a number nconfs of conformers
        """
        for ni in range(self.nconfs):
            cart = copy.deepcopy(ini_cart)
            if ni == 0:
                sample = [0. for di in self.species.conf_dihed]
            else:
                sample = [random.choice([0., 120., 240.]) for di in self.species.conf_dihed]
            for rotor in range(len(self.species.conf_dihed)):
                zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(self.species, rotor, cart, 1)
                zmat[3][2] += sample[rotor]
                for i in range(4, self.species.natom):
                    if zmat_ref[i][2] == 4:
                        zmat[i][2] += sample[rotor]
                    if zmat_ref[i][2] == 1:
                        zmat[i][2] += sample[rotor]
                cart = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref, self.species.natom, self.species.atom, zmatorder)
            self.qc.qc_conf(self.species, cart, self.conf)
            self.conf += 1

        return 0
示例#7
0
    def generate_conformers(self, rotor, cart, print_warning=False):
        """
        Generate guesses for all of the canonical conformers.
        This is a recursive routine to generate them.
        rotor: the rotor number in the order it was discovered
        if -999, then just do a single calculation at the given geometry
        """
        if self.cyc_conf == 0:
            cycles = 1
        else:
            cycles = self.cyc_conf

        name = self.get_name()

        # what is the value of cycles
        # what is value of all things associated w/ conf generation
        # what is length of conf_dihed?
        theoretical_confs = np.power(self.grid, len(
            self.species.conf_dihed)) * cycles

        if rotor != -999:
            if len(self.species.conf_dihed
                   ) > self.max_dihed or theoretical_confs > self.nconfs:
                if rotor == 0:
                    if self.info:
                        logging.info(
                            'Random conformer search is carried out for {}.'.
                            format(name))
                        self.info = False

                    # skipping generation if done
                    if self.cyc_conf > 1:
                        nrandconf = int(round(self.nconfs / self.cyc_conf) + 2)
                    else:
                        nrandconf = self.nconfs
                    if os.path.exists('{}.log'.format(
                            self.get_job_name(nrandconf - 1)
                    )) and os.path.exists('conf/{}_low.log'.format(name)):
                        rows = self.db.select(
                            name=self.get_job_name(nrandconf - 1))
                        for row in rows:
                            self.conf = nrandconf
                            logging.info(
                                'Last conformer was found in kinbot.db, generation is skipped for {}.'
                                .format(self.get_job_name(nrandconf)))
                            logging.info(
                                'Make sure the files are correct, you can reactivate calcs by deleting the last log file.'
                            )
                            return 1

                self.generate_conformers_random_sampling(cart)
                return 0

        # retraction from the recursion
        if rotor == len(self.species.conf_dihed) or rotor == -999:
            self.qc.qc_conf(self.species,
                            cart,
                            self.conf,
                            semi_emp=self.semi_emp)
            if self.conf == 0:
                logging.info(
                    'Theoretical number of conformers is {} for {}.'.format(
                        theoretical_confs, name))
            self.conf += 1
            return 0

        # skipping generation if done
        if os.path.exists('{}.log'.format(
                self.get_job_name(theoretical_confs - 1))) and os.path.exists(
                    'conf/{}_low.log'.format(name)):
            rows = self.db.select(name=self.get_job_name(theoretical_confs -
                                                         1))
            for row in rows:
                self.conf = theoretical_confs
                if print_warning:
                    logging.info(
                        'Theoretical number of conformers is {} for {}.'.
                        format(theoretical_confs, name))
                    logging.info(
                        'Last conformer was found in kinbot.db, generation is skipped for {}.'
                        .format(name))
                    logging.info(
                        'Make sure the files are correct, you can reactivate calcs by deleting the last log file.'
                    )
                return 1

        cart = np.asarray(cart)
        zmat_atom, zmat_ref, zmat, zmatorder = zmatrix.make_zmat_from_cart(
            self.species, rotor, cart, 1)

        rotor += 1

        for gr in range(self.grid):
            zmat[3][2] += 360. / self.grid
            for i in range(4, self.species.natom):
                if zmat_ref[i][2] == 4:
                    zmat[i][2] += 360. / self.grid
                if zmat_ref[i][2] == 1:
                    zmat[i][2] += 360. / self.grid
            cartmod = zmatrix.make_cart_from_zmat(zmat, zmat_atom, zmat_ref,
                                                  self.species.natom,
                                                  self.species.atom, zmatorder)
            self.generate_conformers(rotor, cartmod)

        return 0
示例#8
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
示例#9
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