Exemplo n.º 1
0
def test_attack_cost():

    subst_centers = get_substitution_centres(reactant=reac_complex,
                                             bond_rearrangement=bond_rearr,
                                             shift_factor=2)

    atoms = [
        Atom('F', -2.99674, -0.35248, 0.17493),
        Atom('Cl', 1.63664, 0.02010, -0.05829),
        Atom('C', -0.14524, -0.00136, 0.00498),
        Atom('H', -0.52169, -0.54637, -0.86809),
        Atom('H', -0.45804, -0.50420, 0.92747),
        Atom('H', -0.51166, 1.03181, -0.00597)
    ]

    ideal_complex = ReactantComplex(f, ch3cl)
    ideal_complex.set_atoms(atoms)

    attack_cost = substitution.attack_cost(reac_complex,
                                           subst_centers,
                                           attacking_mol_idx=0)
    ideal_attack_cost = substitution.attack_cost(ideal_complex,
                                                 subst_centers,
                                                 attacking_mol_idx=0)

    # The cost function should be larger for the randomly located reaction
    # complex compared to the ideal
    assert attack_cost > ideal_attack_cost
Exemplo n.º 2
0
def test_attack_cost():

    subst_centers = substitution.get_substitution_centres(reactant=reac_complex,
                                                          bond_rearrangement=bond_rearr,
                                                          shift_factor=2)

    ideal_complex = ReactantComplex(f, ch3cl)
    ideal_complex.set_atoms(atoms=xyz_file_to_atoms(os.path.join(here, 'data', 'sn2_reac_complex.xyz')))

    attack_cost = substitution.attack_cost(reac_complex, subst_centers, attacking_mol_idx=0)
    ideal_attack_cost = substitution.attack_cost(ideal_complex, subst_centers, attacking_mol_idx=0)

    # The cost function should be larger for the randomly located reaction complex compared to the ideal
    assert attack_cost > ideal_attack_cost
Exemplo n.º 3
0
def test_subst():

    reactant = Reactant(name='sn2_r', atoms=xyz_file_to_atoms('reactant.xyz'))

    # SN2' bond rearrangement
    bond_rearr = BondRearrangement(forming_bonds=[(0, 1)],
                                   breaking_bonds=[(3, 4)])

    subst_centers = get_substitution_centres(reactant,
                                             bond_rearr,
                                             shift_factor=1.0)

    assert len(subst_centers) == 1

    # get_substitution_centres should add a dummy atom so the ACX angle is
    # defined
    assert len(reactant.atoms) == 11
Exemplo n.º 4
0
def test_subst_centre():

    subst_centers = substitution.get_substitution_centres(
        reactant=reac_complex, bond_rearrangement=bond_rearr, shift_factor=2)
    # Only one atom gets attacked in an SN2
    assert len(subst_centers) == 1

    sc = subst_centers[0]
    assert type(sc) is substitution.SubstitutionCentre
    assert reac_complex.atoms[sc.a_atom].label == 'F'
    assert reac_complex.atoms[sc.c_atom].label == 'C'
    assert reac_complex.atoms[sc.x_atom].label == 'Cl'

    # The attacking flouride ion doesn't have any nearest neighbours
    assert len(sc.a_atom_nn) == 0

    # The attacking atom to substitution centre atom ideal bond length
    # should be ~ 3 Å
    assert type(sc.r0_ac) is float
    assert 2.0 < sc.r0_ac < 5.0
Exemplo n.º 5
0
def translate_rotate_reactant(reactant,
                              bond_rearrangement,
                              shift_factor,
                              n_iters=10):
    """
    Shift a molecule in the reactant complex so that the attacking atoms
    (a_atoms) are pointing towards the attacked atoms (l_atoms)

    Arguments:
        reactant (autode.complex.ReactantComplex):
        bond_rearrangement (autode.bond_rearrangement.BondRearrangement):
        shift_factor (float):
        n_iters (int): Number of iterations of translation/rotation to perform
                       to (hopefully) find the global minima
    """
    if not hasattr(reactant, 'molecules'):
        logger.warning('Cannot rotate/translate component, not a Complex')
        return

    if len(reactant.molecules) < 2:
        logger.info('Reactant molecule does not need to be translated or '
                    'rotated')
        return

    logger.info('Rotating/translating into a reactive conformation... running')

    # This function can add dummy atoms for e.g. SN2' reactions where there
    # is not a A -- C -- Xattern for the substitution centre
    subst_centres = get_substitution_centres(reactant,
                                             bond_rearrangement,
                                             shift_factor=shift_factor)

    if all(sc.a_atom in reactant.get_atom_indexes(mol_index=0)
           for sc in subst_centres):
        attacking_mol = 0
    else:
        attacking_mol = 1

    # Disable the logger to prevent rotation/translations printing
    logger.disabled = True

    # Find the global minimum for inplace rotation, translation and rotation
    min_cost, opt_x = None, None

    for _ in range(n_iters):
        res = minimize(get_cost_rotate_translate,
                       x0=np.random.random(11),
                       method='BFGS',
                       tol=0.1,
                       args=(reactant, subst_centres, attacking_mol))

        if min_cost is None or res.fun < min_cost:
            min_cost = res.fun
            opt_x = res.x

    # Renable the logger
    logger.disabled = False
    logger.info(f'Minimum cost for translating/rotating is {min_cost:.3f}')

    # Translate/rotation the attacking molecule optimally
    reactant.rotate_mol(axis=opt_x[:3],
                        theta=opt_x[3],
                        mol_index=attacking_mol)
    reactant.translate_mol(vec=opt_x[4:7], mol_index=attacking_mol)
    reactant.rotate_mol(axis=opt_x[7:10],
                        theta=opt_x[10],
                        mol_index=attacking_mol)

    logger.info('                                                 ... done')
    reactant.print_xyz_file()

    # Remove any dummy atoms that may have been added
    # in alt_substitution_centres
    reactant.atoms = [atom for atom in reactant.atoms if atom.label != 'D']

    return None