Exemple #1
0
 def _weight(atoms, coords3d, indices, f_damping):
     m, o, p, n = indices
     rho_mo = Torsion.rho(atoms, coords3d, (m, o))
     rho_op = Torsion.rho(atoms, coords3d, (o, p))
     rho_pn = Torsion.rho(atoms, coords3d, (p, n))
     rad_mop = Bend._calculate(coords3d, (m, o, p))
     rad_opn = Bend._calculate(coords3d, (o, p, n))
     return (
         (rho_mo * rho_op * rho_pn)**(1/3)
         * (f_damping + (1-f_damping)*sin(rad_mop))
         * (f_damping + (1-f_damping)*sin(rad_opn))
     )
Exemple #2
0
def get_linear_bend_inds(coords3d,
                         cbm,
                         bends,
                         min_deg=175,
                         max_bonds=4,
                         logger=None):
    linear_bends = list()
    complements = list()

    if min_deg is None:
        return linear_bends, complements

    bm = squareform(cbm)
    for bend in bends:
        deg = np.rad2deg(Bend._calculate(coords3d, bend))
        bonds = sum(bm[bend[1]])
        if (deg >= min_deg) and (bonds <= max_bonds):
            log(
                logger,
                f"Bend {bend}={deg:.1f}° is (close to) linear. "
                "Creating linear bend & complement.",
            )
            linear_bends.append(bend)
            complements.append(bend)
    return linear_bends, complements
Exemple #3
0
def get_hydrogen_bond_inds(atoms, coords3d, bond_inds, logger=None):
    tmp_sets = [frozenset(bi) for bi in bond_inds]
    # Check for hydrogen bonds as described in [1] A.1 .
    # Find hydrogens bonded to small electronegative atoms X = (N, O
    # F, P, S, Cl).
    hydrogen_inds = [i for i, a in enumerate(atoms) if a.lower() == "h"]
    x_inds = [
        i for i, a in enumerate(atoms) if a.lower() in "n o f p s cl".split()
    ]
    hydrogen_bond_inds = list()
    for h_ind, x_ind in it.product(hydrogen_inds, x_inds):
        as_set = set((h_ind, x_ind))
        if as_set not in tmp_sets:
            continue
        # Check if distance of H to another electronegative atom Y is
        # greater than the sum of their covalent radii but smaller than
        # the 0.9 times the sum of their van der Waals radii. If the
        # angle X-H-Y is greater than 90° a hydrogen bond is asigned.
        y_inds = set(x_inds) - set((x_ind, ))
        for y_ind in y_inds:
            y_atom = atoms[y_ind].lower()
            cov_rad_sum = CR["h"] + CR[y_atom]
            distance = Stretch._calculate(coords3d, (h_ind, y_ind))
            vdw = 0.9 * (VDW_RADII["h"] + VDW_RADII[y_atom])
            angle = Bend._calculate(coords3d, (x_ind, h_ind, y_ind))
            if (cov_rad_sum < distance < vdw) and (angle > np.pi / 2):
                hydrogen_bond_inds.append((h_ind, y_ind))
                log(
                    logger,
                    f"Detected hydrogen bond between atoms {h_ind} "
                    f"({atoms[h_ind]}) and {y_ind} ({atoms[y_ind]})",
                )

    return hydrogen_bond_inds
def test_bend(deg):
    indices = [1, 0, 2]

    zmat_str = f"""
    C
    C 1 1.5
    C 1 1.5 2 {deg}
    """.strip()
    zmat = zmat_from_str(zmat_str)
    geom = geom_from_zmat(zmat)
    coords3d = geom.coords3d

    # Explicitly implemented
    # Gradient returned in order [0, 1, 2]
    val, grad = Bend._calculate(coords3d, indices, gradient=True)

    # Reference values, code generated
    args = coords3d[indices].flatten()
    ref_val = q_a(*args)
    # Reference gradient returned in order [1, 0, 2]
    _ref_grad = dq_a(*args)
    ref_grad = np.zeros_like(coords3d)
    ref_grad[indices] = _ref_grad.reshape(-1, 3)

    mp_ref_val = mp_d.q_a(*args)
    _mp_ref_grad = mp_d.dq_a(*args)
    mp_ref_grad = np.zeros_like(coords3d)
    mp_ref_grad[indices] = _mp_ref_grad.reshape(-1, 3)

    assert val == pytest.approx(ref_val)
    assert val == pytest.approx(mp_ref_val)
    np.testing.assert_allclose(grad.flatten(), ref_grad.flatten(), atol=1e-12)
    np.testing.assert_allclose(grad.flatten(),
                               mp_ref_grad.flatten(),
                               atol=1e-12)

    # Code generated 2nd derivative
    dgrad = d2q_a(*args)
    mp_dgrad = mp_d.d2q_a(*args)

    # Finite difference reference values
    ref_dgrad = fin_diff_B(Bend(indices), coords3d)
    np.testing.assert_allclose(dgrad, ref_dgrad, atol=1e-9)
    np.testing.assert_allclose(mp_dgrad, ref_dgrad, atol=1e-9)
Exemple #5
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
Exemple #6
0
def bend_valid(coords3d, indices, min_deg, max_deg):
    val = Bend._calculate(coords3d, indices)
    deg = np.rad2deg(val)
    return min_deg <= deg <= max_deg
Exemple #7
0
def bend_still_valid(coords3d, indices, min_deg, max_deg):
    val = Bend._calculate(coords3d, indices)
    deg = np.rad2deg(val)
    # Less than, not less or equal as in "bend_valid"
    return min_deg <= deg < max_deg