예제 #1
0
def attack_cost(reactant, subst_centres, attacking_mol_idx,
                a=1.0, b=1.0, c=1.0, d=10.0):
    """
    Calculate the 'attack cost' for a molecule attacking in e.g. a
    substitution or elimination reaction::

        C = Σ_ac a * (r_ac - r^0_ac)^2  +  Σ_acx b * (1 - cos(θ))  +
                  Σ_acx c*(1 + cos(φ))  +  Σ_ij d/r_ij^4

    where::

        cos(θ) = (v_ann • v_cx / |v_ann||v_cx|)
        cos(φ) = (v_ca • v_cx / |v_ca||v_cx|)

    Returns:
        (float): Cost
    """
    coords = reactant.get_coordinates()
    cost = 0

    for subst_centre in subst_centres:

        r_ac = reactant.get_distance(atom_i=subst_centre.a_atom,
                                     atom_j=subst_centre.c_atom)

        cost += a * (r_ac - subst_centre.r0_ac)**2

        # Attack vector is the average of all the nearest neighbour atoms,
        # unless it is flat
        a_nn_coords = [coords[atom_index] - coords[subst_centre.a_atom] for atom_index in subst_centre.a_atom_nn]

        if len(a_nn_coords) == 0:
            # The attacking atom has no nearest neighbours thus take the
            # attack vector to be a unit vector
            v_ann = np.array([1.0, 0.0, 0.0])
        else:
            v_ann = -np.average(np.array(a_nn_coords), axis=0)

        if length(v_ann) < 1E-1:
            # Attacking atom is planar. Compute the perpendicular from two
            # nearest neighbours
            v_ann = np.cross(coords[subst_centre.a_atom] - coords[subst_centre.a_atom_nn[0]],
                             coords[subst_centre.a_atom] - coords[subst_centre.a_atom_nn[1]])

        v_cx = coords[subst_centre.x_atom] - coords[subst_centre.c_atom]

        # b(1 - cos(θ))
        cost += b * (1 - np.dot(v_ann, v_cx) / (length(v_ann) * length(v_cx)))

        v_ca = coords[subst_centre.a_atom] - coords[subst_centre.c_atom]

        # c(1 + cos(φ))
        cost += c * (1 + np.dot(v_ca, v_cx) / (length(v_ca) * length(v_cx)))

        repulsion = reactant.calc_repulsion(mol_index=attacking_mol_idx)
        cost += d * repulsion

    return cost
예제 #2
0
def add_dummy_atom(reactant, bond_rearrangement):
    """
    Add a dummy atom above or below the plane of the reactant as a temporary
    X atom

    Arguments:
        reactant (autode.complex.ReactantComplex):
        bond_rearrangement (autode.bond_rearrangement.BondRearrangement):
    """
    logger.info('Adding dummy X atom so a substitution center can be found')

    fbond = bond_rearrangement.fbonds[0]
    bbond = bond_rearrangement.bbonds[0]

    components = connected_components(reactant.graph)

    if len(components) != 2:
        raise NotImplementedError('Must have two components for dummy add')

    mol1_idxs, mol2_idxs = components

    # Find the central atom as the atom index that is in the forming bond but
    # also contains all indexes of the breaking bond
    if fbond[0] in mol1_idxs and all(idx in mol2_idxs for idx in bbond):
        c_atom = fbond[1]

    else:
        c_atom = fbond[0]

    # Nearest neighbours to the central atom used to generate the normal
    # along which the dummy atom is placed
    c_atom_nns = list(reactant.graph.neighbors(c_atom))

    if len(c_atom_nns) < 2:
        raise NotImplementedError('Cannot place dummy atom')

    cn1, cn2 = c_atom_nns[:2]
    coords = reactant.get_coordinates()

    # Calculate the normal from the vectors to two of the neighbours
    position = np.cross(coords[cn1] - coords[c_atom],
                        coords[cn2] - coords[c_atom])
    position /= length(position)

    # Add the dummy atom to a position on the top/bottom face
    logger.warning('Adding a dummy atom to the set of atoms')
    reactant.atoms.append(DummyAtom(*position))

    # Add the breaking bond to the bond rearrangement temporarily
    bond_rearrangement.bbonds.append([c_atom, len(reactant.atoms) - 1])

    return None
예제 #3
0
파일: species.py 프로젝트: t-young31/autodE
 def get_distance(self, atom_i, atom_j):
     """Get the distance between two atoms in the species"""
     return length(self.atoms[atom_i].coord - self.atoms[atom_j].coord)
예제 #4
0
def test_length():
    assert geom.length(np.ones(3)) == np.linalg.norm(np.ones(3))
예제 #5
0
def test_length():
    assert geom.length(np.array([1.0, 1.0, 1.0])) == np.linalg.norm(
        np.array([1.0, 1.0, 1.0]))