Пример #1
0
 def set_dihedral_index(dihedral_ind, proper=True):
     dihed = tuple(dihedral_ind)
     check_in = proper_dihedral_inds if proper else improper_dihedral_inds
     # Check if this dihedral is already present
     if (dihed in check_in) or (dihed[::-1] in check_in):
         return
     # Assure that the angles are below 175° (3.054326 rad)
     if not dihedral_valid(coords3d, dihedral_ind, deg_thresh=max_deg):
         log_dihed_skip(dihedral_ind)
         return
     if proper:
         proper_dihedral_inds.append(dihed)
     else:
         improper_dihedral_inds.append(dihed)
Пример #2
0
def update_internals(
    new_coords3d,
    old_internals,
    primitives,
    dihedral_inds,
    check_dihedrals=False,
    logger=None,
):
    prim_internals = eval_primitives(new_coords3d, primitives)
    new_internals = [prim_int.val for prim_int in prim_internals]
    internal_diffs = np.array(new_internals) - old_internals

    dihedrals = [prim_internals[i] for i in dihedral_inds]
    dihedral_num = len(dihedrals)
    dihedral_diffs = internal_diffs[-dihedral_num:]

    # Find differences that are shifted by 2*pi
    shifted_by_2pi = np.abs(np.abs(dihedral_diffs) - 2 * np.pi) < np.pi / 2
    new_dihedrals = np.array([dihed.val for dihed in dihedrals])
    if any(shifted_by_2pi):
        new_dihedrals[shifted_by_2pi] -= (
            2 * np.pi * np.sign(dihedral_diffs[shifted_by_2pi]))
        # Update values
        for dihed, new_val in zip(dihedrals, new_dihedrals):
            dihed.val = new_val
    # See if dihedrals became invalid (collinear atoms)
    if check_dihedrals:
        are_valid = [
            dihedral_valid(new_coords3d, prim.inds) for prim in dihedrals
        ]
        try:
            first_dihedral = dihedral_inds[0]
        except IndexError:
            first_dihedral = 0
        invalid_inds = [
            i + first_dihedral for i, is_valid in enumerate(are_valid)
            if not is_valid
        ]
        if len(invalid_inds) > 0:
            invalid_prims = [primitives[i] for i in invalid_inds]
            log(logger,
                "Dihedral(s) became invalid! Need new internal coordinates!")
            raise NeedNewInternalsException(new_coords3d,
                                            invalid_inds=invalid_inds,
                                            invalid_prims=invalid_prims)

    return prim_internals
Пример #3
0
def get_dihedral_inds(coords3d, bond_inds, bend_inds, max_deg, logger=None):
    max_rad = np.deg2rad(max_deg)
    bond_dict = dict()
    for from_, to_ in bond_inds:
        bond_dict.setdefault(from_, list()).append(to_)
        bond_dict.setdefault(to_, list()).append(from_)
    proper_dihedral_inds = list()
    improper_candidates = list()
    improper_dihedral_inds = list()

    def log_dihed_skip(inds):
        log(
            logger,
            f"Skipping generation of dihedral {inds} "
            "as some of the the atoms are (close too) linear.",
        )

    def set_dihedral_index(dihedral_ind, proper=True):
        dihed = tuple(dihedral_ind)
        check_in = proper_dihedral_inds if proper else improper_dihedral_inds
        # Check if this dihedral is already present
        if (dihed in check_in) or (dihed[::-1] in check_in):
            return
        # Assure that the angles are below 175° (3.054326 rad)
        if not dihedral_valid(coords3d, dihedral_ind, deg_thresh=max_deg):
            log_dihed_skip(dihedral_ind)
            return
        if proper:
            proper_dihedral_inds.append(dihed)
        else:
            improper_dihedral_inds.append(dihed)

    for bond, bend in it.product(bond_inds, bend_inds):
        # print("bond", bond, "bend", bend)
        central = bend[1]
        bend_set = set(bend)
        bond_set = set(bond)
        # Check if the two sets share one common atom. If not continue.
        intersect = bend_set & bond_set
        # print("intersect", intersect)
        if len(intersect) != 1:
            continue
        # if bond == frozenset((0, 11)) and bend == (0, 3, 4):
        # import pdb; pdb.set_trace()
        # pass

        # TODO: check collinearity of bond and bend.

        # When the common atom between bond and bend is a terminal, and not a central atom
        # in the bend we create a proper dihedral. Improper dihedrals are only created
        # when no proper dihedrals have been found.
        if central not in bond_set:
            # The new terminal atom in the dihedral is the one, that doesn' intersect.
            terminal = tuple(bond_set - intersect)[0]
            intersecting_atom = tuple(intersect)[0]
            bend_terminal = tuple(bend_set - {central} - intersect)[0]

            bend_rad = Bend._calculate(coords3d, bend)
            # Bend atoms are nearly collinear. Check if we can skip the central bend atom
            # and use an atom that is conneced to the terminal atom of the bend or bond.
            if bend_rad >= max_rad:
                bend_terminal_bonds = set(bond_dict[bend_terminal]) - bend_set
                bond_terminal_bonds = set(bond_dict[terminal]) - bond_set
                set_dihedrals = [
                    (terminal, intersecting_atom, bend_terminal, betb)
                    for betb in bend_terminal_bonds
                ] + [(bend_terminal, intersecting_atom, terminal, botb)
                     for botb in bond_terminal_bonds]
                # Hardcoded for now ... look ahead to next shell of atoms
                if not any([
                        dihedral_valid(coords3d, inds, deg_thresh=max_deg)
                        for inds in set_dihedrals
                ]):
                    set_dihedrals = []
                    for betb in bend_terminal_bonds:
                        bend_terminal_bonds_v2 = set(
                            bond_dict[betb]) - bend_set - bond_set
                        set_dihedrals = [(terminal, intersecting_atom, betb,
                                          betb_v2)
                                         for betb_v2 in bend_terminal_bonds_v2]
                    for botb in bond_terminal_bonds:
                        bond_terminal_bonds_v2 = set(
                            bond_dict[botb]) - bend_set - bond_set
                        set_dihedrals = [(bend_terminal, intersecting_atom,
                                          botb, botb_v2)
                                         for botb_v2 in bond_terminal_bonds_v2]
            elif intersecting_atom == bend[0]:
                set_dihedrals = [[terminal] + list(bend)]
            else:
                set_dihedrals = [list(bend) + [terminal]]
            [set_dihedral_index(dihed) for dihed in set_dihedrals]
        # If the common atom is the central atom we try to form an out
        # of plane bend / improper torsion. They may be created later on.
        else:
            fourth_atom = list(bond_set - intersect)
            dihedral_ind = list(bend) + fourth_atom
            # This way dihedrals may be generated that contain linear
            # atoms and these would be undefinied. So we check for this.
            if dihedral_valid(coords3d, dihedral_ind, deg_thresh=max_deg):
                improper_candidates.append(dihedral_ind)
            else:
                log_dihed_skip(dihedral_ind)

    # Now try to create the remaining improper dihedrals.
    if (len(coords3d) >= 4) and (len(proper_dihedral_inds) == 0):
        log(
            logger,
            "Could not define any proper dihedrals! Generating improper dihedrals!",
        )
        for improp in improper_candidates:
            set_dihedral_index(improp, proper=False)
        log(
            logger,
            "Permutational symmetry not considerd in generation of "
            "improper dihedrals.",
        )

    return proper_dihedral_inds, improper_dihedral_inds