예제 #1
0
def test_get_bond_rearrangs():

    if os.path.exists('test_bond_rearrangs.txt'):
        os.remove('test_bond_rearrangs.txt')

    # ethane --> Ch3 + Ch3
    reac = Molecule(smiles='CC')
    prod = Molecule(atoms=[Atom('C', -8.3, 1.4, 0.0),
                           Atom('C', 12, 1.7, -0.0),
                           Atom('H', -8.6, 0.5, -0.5),
                           Atom('H', -8.6, 2.3, -0.4),
                           Atom('H', -8.6, 1.3, 1),
                           Atom('H', 12.3, 1.7, -1.0),
                           Atom('H', 12.4, 0.8, 0.4),
                           Atom('H', 12.3, 2.5, 0.5)])

    assert br.get_bond_rearrangs(ReactantComplex(reac), ProductComplex(prod), name='test') == [br.BondRearrangement(breaking_bonds=[(0, 1)])]

    # Rerunning the get function should read test_bond_rearrangs.txt, so modify it, swapping 0 and 1 in the breaking
    # bond then reopen
    with open('test_bond_rearrangs.txt', 'w') as rearr_file:
        print('fbond\n'
              'bbonds\n'
              '1 0\n'
              'end', file=rearr_file)

    rearr = br.get_bond_rearrangs(ReactantComplex(reac), ProductComplex(prod), name='test')[0]
    assert rearr == BondRearrangement(breaking_bonds=[(1, 0)])

    assert br.get_bond_rearrangs(ReactantComplex(prod), ProductComplex(reac), name='test2') is None

    # If reactants and products are identical then the rearrangement is undetermined
    assert br.get_bond_rearrangs(ReactantComplex(reac), ProductComplex(reac), name='test3') is None

    os.remove('test_bond_rearrangs.txt')
예제 #2
0
def test_calc_delta_e():

    r1 = reaction.Reactant(name='h', atoms=[Atom('H', 0.0, 0.0, 0.0)])
    r1.energy = -0.5

    r2 = reaction.Reactant(name='h', atoms=[Atom('H', 0.0, 0.0, 0.0)])
    r2.energy = -0.5

    tsguess = TSguess(atoms=None,
                      reactant=ReactantComplex(r1),
                      product=ProductComplex(r2))
    tsguess.bond_rearrangement = BondRearrangement()
    ts = TransitionState(tsguess)
    ts.energy = -0.8

    p = reaction.Product(
        name='hh', atoms=[Atom('H', 0.0, 0.0, 0.0),
                          Atom('H', 1.0, 0.0, 0.0)])
    p.energy = -1.0

    reac = reaction.Reaction(r1, r2, p)
    reac.ts = ts

    assert -1E-6 < reac.calc_delta_e() < 1E-6
    assert 0.2 - 1E-6 < reac.calc_delta_e_ddagger() < 0.2 + 1E-6
예제 #3
0
def test_sum_mep():
    reactant = ReactantComplex(Molecule(smiles='C', charge=0, mult=1))
    product = ProductComplex(Molecule(smiles='C', charge=0, mult=1))
    product.graph.remove_edge(0, 1)
    product.graph.remove_edge(0, 2)

    # Fictitious PES
    pes = PES2d(reactant,
                product,
                r1s=np.linspace(1, 2, 3),
                r1_idxs=(0, 1),
                r2s=np.linspace(1, 2, 3),
                r2_idxs=(0, 2))

    # Energies are all 0 apart from at the 'saddle point' (1, 1)
    for i in range(3):
        for j in range(3):
            pes.species[i, j] = deepcopy(reactant)
            pes.species[i, j].energy = 0

            if i == j == 2:
                pes.species[i, j].graph = product.graph

    pes.species[1, 1].energy = 1
    mep_sum = mep.get_sum_energy_mep(saddle_point_r1r2=(1.5, 1.5), pes_2d=pes)

    # Energy over the saddle point is 1 both sides -> 2 Ha
    assert mep_sum == 2
예제 #4
0
def test_constrained_opt():
    os.chdir(os.path.join(here, 'data'))

    mol = Molecule(name='h3',
                   mult=2,
                   charge=0,
                   atoms=[
                       Atom('H', 0.0, 0.0, 0.0),
                       Atom('H', 0.7, 0.0, 0.0),
                       Atom('H', 1.7, 0.0, 0.0)
                   ])

    Config.XTB.path = here  # A path that exists

    ts_guess = get_ts_guess_constrained_opt(
        reactant=ReactantComplex(mol),
        distance_consts={(0, 1): 1.0},
        method=orca,
        keywords=Config.ORCA.keywords.low_opt,
        name='template_ts_guess',
        product=ProductComplex(mol))
    assert ts_guess.n_atoms == 3

    os.remove('xcontrol_template_ts_guess_constrained_opt_ll_xtb')
    os.remove('template_ts_guess_constrained_opt_ll_xtb.xyz')
    os.remove('template_ts_guess_constrained_opt_orca.inp')
    os.chdir(here)
예제 #5
0
def test_reaction_warnings():
    test_reac = Reactant(name='test', smiles='C')
    test_reac.energy = -1

    test_prod = Product(name='test', smiles='C')
    test_prod.energy = -1.03187251

    tsguess = TSguess(atoms=test_reac.atoms,
                      reactant=ReactantComplex(test_reac),
                      product=ProductComplex())
    tsguess.bond_rearrangement = BondRearrangement()
    ts = TransitionState(tsguess)
    ts.energy = -0.98
    ts.imaginary_frequencies = [-100]

    reaction = Reaction(test_reac, test_prod)
    reaction.ts = None

    # Should be some warning with no TS
    assert len(
        plotting.get_reaction_profile_warnings(reactions=[reaction])) > 10

    # Should be no warnings  with a TS that exists and has an energy and one
    # imaginary freq
    reaction.ts = ts
    warnings = plotting.get_reaction_profile_warnings(reactions=[reaction])
    assert 'None' in warnings
예제 #6
0
def test_plot_reaction_profile():

    r = Reactant(name='reactant', smiles='C')
    p = Product(name='product', smiles='C')
    tsguess = TSguess(atoms=r.atoms,
                      reactant=ReactantComplex(r),
                      product=ProductComplex(p))
    tsguess.bond_rearrangement = BondRearrangement()
    ts = TransitionState(tsguess)
    reaction = Reaction(r, p)
    reaction.ts = ts

    plotting.plot_reaction_profile(reactions=[reaction],
                                   units=KjMol,
                                   name='test')

    assert os.path.exists('test_reaction_profile.png')
    os.remove('test_reaction_profile.png')

    with pytest.raises(AssertionError):
        plotting.plot_reaction_profile(reactions=[reaction],
                                       units=KjMol,
                                       name='test',
                                       free_energy=True,
                                       enthalpy=True)
    return None
예제 #7
0
def test_3b():
    reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('H', 0.6, 0, 0), Atom('H', 1.2, 0, 0), Atom('H', 1.8, 0, 0)])
    make_graph(reac, allow_invalid_valancies=True)
    prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('H', 10, 0, 0), Atom('H', 20, 0, 0), Atom('H', 30, 0, 0)])

    # Reactants to products must break three bonds but this is not yet supported in any form
    assert br.get_bond_rearrangs(ReactantComplex(reac), ProductComplex(prod), name='3b_test') is None
예제 #8
0
def test_ts_conformer(tmpdir):
    os.chdir(tmpdir)

    ch3cl = Reactant(charge=0,
                     mult=1,
                     atoms=[
                         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)
                     ])
    f = Reactant(charge=-1, mult=1, atoms=[Atom('F', 4.0, 0.0, 0.0)])

    ch3f = Product(charge=0,
                   mult=1,
                   atoms=[
                       Atom('C', -0.05250, 0.00047, -0.00636),
                       Atom('F', 1.31229, -0.01702, 0.16350),
                       Atom('H', -0.54993, -0.04452, 0.97526),
                       Atom('H', -0.34815, 0.92748, -0.52199),
                       Atom('H', -0.36172, -0.86651, -0.61030)
                   ])
    cl = Reactant(charge=-1, mult=1, atoms=[Atom('Cl', 4.0, 0.0, 0.0)])

    f_ch3cl_tsguess = TSguess(reactant=ReactantComplex(f, ch3cl),
                              product=ProductComplex(ch3f, cl),
                              atoms=[
                                  Atom('F', -2.66092, -0.01426, 0.09700),
                                  Atom('Cl', 1.46795, 0.05788, -0.06166),
                                  Atom('C', -0.66317, -0.01826, 0.02488),
                                  Atom('H', -0.78315, -0.58679, -0.88975),
                                  Atom('H', -0.70611, -0.54149, 0.97313),
                                  Atom('H', -0.80305, 1.05409, 0.00503)
                              ])

    f_ch3cl_tsguess.bond_rearrangement = BondRearrangement(breaking_bonds=[
        (2, 1)
    ],
                                                           forming_bonds=[(0,
                                                                           2)])

    f_ch3cl_ts = TransitionState(ts_guess=f_ch3cl_tsguess)

    atoms = conf_gen.get_simanl_atoms(
        species=f_ch3cl_ts, dist_consts=get_distance_constraints(f_ch3cl_ts))

    regen = Molecule(name='regenerated_ts', charge=-1, mult=1, atoms=atoms)
    # regen.print_xyz_file()

    # Ensure the making/breaking bonds retain their length
    regen_coords = regen.get_coordinates()
    assert are_coords_reasonable(regen_coords) is True

    assert 1.9 < np.linalg.norm(regen_coords[0] - regen_coords[2]) < 2.1
    assert 2.0 < np.linalg.norm(regen_coords[1] - regen_coords[2]) < 2.2

    os.chdir(here)
예제 #9
0
def test_2b():
    reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('H', 0.6, 0, 0), Atom('H', 1.2, 0, 0)])
    make_graph(reac, allow_invalid_valancies=True)
    prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('H', 10, 0, 0), Atom('H', 20, 0, 0)])

    # Reactants to products must break two bonds
    assert len(br.get_bond_rearrangs(ReactantComplex(reac), ProductComplex(prod), name='2b_test')) == 1
    os.remove('2b_test_bond_rearrangs.txt')

    assert br.get_fbonds_bbonds_2b(reac, prod, [], [[(0, 1), (1, 2)]], [], [], [(0, 2)], []) == [br.BondRearrangement(breaking_bonds=[(0, 1), (1, 2)])]
예제 #10
0
def test_two_possibles():

    ch2ch3f = Molecule(name='radical', charge=0, mult=2,
                       smiles='FC[C]([H])[H]')

    ch3ch2f = Molecule(name='radical', charge=0, mult=2,
                       smiles='C[C]([H])F')

    rearrs = br.get_bond_rearrangs(ReactantComplex(ch2ch3f), ProductComplex(ch3ch2f),
                                   name='H_migration')

    # There are two possibilities for H migration by they should be considered the same
    assert len(rearrs) == 1
    os.remove('H_migration_bond_rearrangs.txt')
예제 #11
0
def test_multiple_possibilities():
    r1 = Molecule(name='h_dot', smiles='[H]')
    r2 = Molecule(name='methane', smiles='C')
    p1 = Molecule(name='h2', smiles='[HH]')
    p2 = Molecule(name='ch3_dot', smiles='[CH3]')

    reac = ReactantComplex(r1, r2)
    reac.print_xyz_file()

    rearrs = br.get_bond_rearrangs(reac, ProductComplex(p1, p2),
                                   name='H_subst')
    os.remove('H_subst_bond_rearrangs.txt')

    # All H abstractions are the same
    assert len(rearrs) == 1
예제 #12
0
def test_plot_reaction_profile():

    r = Reactant(name='reactant', smiles='C')
    p = Product(name='product', smiles='C')
    tsguess = TSguess(atoms=r.atoms,
                      reactant=ReactantComplex(r),
                      product=ProductComplex(p))
    tsguess.bond_rearrangement = BondRearrangement()
    ts = TransitionState(tsguess)
    reaction = Reaction(r, p)
    reaction.ts = ts

    plotting.plot_reaction_profile(reactions=[reaction],
                                   units=KjMol,
                                   name='test_reaction')

    assert os.path.exists('test_reaction_reaction_profile.png')
    os.remove('test_reaction_reaction_profile.png')
예제 #13
0
def test_plot_reaction_profile():
    # only tests the file is created with the right name
    os.chdir(os.path.join(here, 'data'))

    r = Reactant(name='reactant', smiles='C')
    p = Product(name='product', smiles='C')
    tsguess = TSguess(atoms=r.atoms, reactant=ReactantComplex(r), product=ProductComplex(p))
    tsguess.bond_rearrangement = BondRearrangement()
    ts = TransitionState(tsguess)
    reaction = Reaction(r, p)
    reaction.ts = ts

    plotting.plot_reaction_profile(reactions=[reaction], units=KjMol, name='test_reaction')

    assert os.path.exists('test_reaction_reaction_profile.png')

    os.remove('test_reaction_reaction_profile.png')
    os.chdir(here)
예제 #14
0
def test_constrained_opt():

    mol = Molecule(name='h3',
                   mult=2,
                   charge=0,
                   atoms=[
                       Atom('H', 0.0, 0.0, 0.0),
                       Atom('H', 0.7, 0.0, 0.0),
                       Atom('H', 1.7, 0.0, 0.0)
                   ])

    # Spoof an XTB install
    Config.XTB.path = here

    ts_guess = get_ts_guess_constrained_opt(
        reactant=ReactantComplex(mol),
        distance_consts={(0, 1): 1.0},
        method=XTB(),
        keywords=Config.XTB.keywords.low_opt,
        name='template_ts_guess',
        product=ProductComplex(mol))
    assert ts_guess.n_atoms == 3
예제 #15
0
def test_fb_rp_isomorphic():

    reac = ReactantComplex(f, ch3cl)
    prod = ProductComplex(ch3f, cl)

    assert f_b_isomorphic_to_r_p(forwards=prod,
                                 backwards=reac,
                                 reactant=reac,
                                 product=prod)

    assert f_b_isomorphic_to_r_p(forwards=reac,
                                 backwards=prod,
                                 reactant=reac,
                                 product=prod)

    assert not f_b_isomorphic_to_r_p(
        forwards=reac, backwards=reac, reactant=reac, product=prod)

    # Check for e.g. failed optimisation of the forwards displaced complex
    mol_no_atoms = Product()
    assert not f_b_isomorphic_to_r_p(
        forwards=mol_no_atoms, backwards=reac, reactant=reac, product=prod)
예제 #16
0
def test_calculate_reaction_profile_energies():

    test_reac = Reactant(name='test', smiles='C')
    test_reac.energy = -1

    test_prod = Product(name='test', smiles='C')
    test_prod.energy = -1.03187251

    tsguess = TSguess(atoms=test_reac.atoms,
                      reactant=ReactantComplex(test_reac),
                      product=ProductComplex())

    tsguess.bond_rearrangement = BondRearrangement()
    ts = TransitionState(tsguess)
    ts.energy = -0.96812749

    reaction = Reaction(test_reac, test_prod)
    reaction.ts = ts

    energies = plotting.calculate_reaction_profile_energies(
        reactions=[reaction], units=KcalMol)

    # Energies have been set to ∆E = -20 and ∆E‡ = 20 kcal mol-1 respectively
    assert energies[0].item() == 0
    assert 19 < energies[1].item() < 21
    assert -21 < energies[2].item() < -19

    # Copying the reaction should give relative energies [0, 20, -20, 0, -40]

    energies = plotting.calculate_reaction_profile_energies(
        reactions=[reaction, deepcopy(reaction)], units=KcalMol)

    # Energies have been set to ∆E = -20 and ∆E‡ = 20 kcal mol-1 respectively
    assert energies[0].item() == 0
    assert -0.1 < energies[3].item() < 0.1
    assert -41 < energies[4].item() < -39
예제 #17
0
                     Atom('H', -0.51166, 1.03181, -0.00597)
                 ])
f = Reactant(charge=-1, mult=1, atoms=[Atom('F', 4.0, 0.0, 0.0)])
reac_complex = ReactantComplex(f, ch3cl)

ch3f = Product(charge=0,
               mult=1,
               atoms=[
                   Atom('C', -0.05250, 0.00047, -0.00636),
                   Atom('F', 1.31229, -0.01702, 0.16350),
                   Atom('H', -0.54993, -0.04452, 0.97526),
                   Atom('H', -0.34815, 0.92748, -0.52199),
                   Atom('H', -0.36172, -0.86651, -0.61030)
               ])
cl = Product(charge=-1, mult=1, atoms=[Atom('Cl', 4.0, 0.0, 0.0)])
product_complex = ProductComplex(ch3f, cl)


@testutils.work_in_zipped_dir(os.path.join(here, 'data', 'ts_guess.zip'))
def test_ts_template_save():

    ts_graph = reac_complex.graph.copy()

    # Add the F-C bond as active
    ts_graph.add_edge(0, 2, active=True)

    # Remove then re-add the C-Cl bond as active
    ts_graph.remove_edge(1, 2)
    ts_graph.add_edge(1, 2, active=True)

    truncated_graph = get_truncated_active_mol_graph(ts_graph)
예제 #18
0
from autode.pes.pes import get_closest_species
from autode.species.complex import ReactantComplex, ProductComplex
from autode.atoms import Atom
from autode.species.species import Species
from autode.mol_graphs import make_graph
from autode.exceptions import NoClosestSpecies
from autode.pes.pes import FormingBond, BreakingBond
from autode.reactions.reaction import Reaction
from autode.species.molecule import Reactant, Product
import pytest
import numpy as np

mol = Species(name='H2', charge=0, mult=1, atoms=[Atom('H'), Atom('H', z=1.0)])
make_graph(mol)
reactant = ReactantComplex(mol, mol)
product = ProductComplex(mol, mol)

pes = PES2d(reactant=reactant,
            product=reactant,
            r1s=np.linspace(1, 3, 3),
            r1_idxs=(0, 1),
            r2s=np.linspace(1, 0, 2),
            r2_idxs=(2, 3))


def test_2d_pes_class():

    assert reactant.n_atoms == 4

    assert pes.rs.shape == (3, 2)
    assert pes.species.shape == (3, 2)
예제 #19
0
def test_get_ts_guess_2dscan():

    ch3cl_f = Reactant(name='CH3Cl_F-',
                       charge=-1,
                       mult=1,
                       atoms=[
                           Atom('F', -4.14292, -0.24015, 0.07872),
                           Atom('Cl', 1.63463, 0.09787, -0.02490),
                           Atom('C', -0.14523, -0.00817, 0.00208),
                           Atom('H', -0.47498, -0.59594, -0.86199),
                           Atom('H', -0.45432, -0.49900, 0.93234),
                           Atom('H', -0.56010, 1.00533, -0.04754)
                       ])

    ch3f_cl = Product(name='CH3Cl_F-',
                      charge=-1,
                      mult=1,
                      atoms=[
                          Atom('F', 1.63463, 0.09787, -0.02490),
                          Atom('Cl', -4.14292, -0.24015, 0.07872),
                          Atom('C', -0.14523, -0.00817, 0.00208),
                          Atom('H', -0.47498, -0.59594, -0.86199),
                          Atom('H', -0.45432, -0.49900, 0.93234),
                          Atom('H', -0.56010, 1.00533, -0.04754)
                      ])

    #         H                H
    #   F-   C--Cl     ->   F--C         Cl-
    #       H H               H H
    pes = pes_2d.PES2d(reactant=ReactantComplex(ch3cl_f),
                       product=ProductComplex(ch3f_cl),
                       r1s=np.linspace(4.0, 1.5, 9),
                       r1_idxs=(0, 2),
                       r2s=np.linspace(1.78, 4.0, 8),
                       r2_idxs=(1, 2))

    pes.calculate(name='SN2_PES', method=xtb, keywords=xtb.keywords.low_opt)

    assert pes.species[0, 1] is not None
    assert -13.13 < pes.species[0, 1].energy < -13.11
    assert pes.species.shape == (9, 8)
    assert pes.rs.shape == (9, 8)
    assert type(pes.rs[0, 1]) == tuple
    assert pes.rs[1, 1] == (np.linspace(4.0, 1.5,
                                        9)[1], np.linspace(1.78, 4.0, 8)[1])

    # Fitting the surface with a 2D polynomial up to order 3 in r1 and r2 i.e.
    #  r1^3r2^3
    pes.fit(polynomial_order=3)
    assert pes.coeff_mat is not None
    assert pes.coeff_mat.shape == (4, 4)  # Includes r1^0 etc.

    pes.print_plot(name='pes_plot')
    assert os.path.exists('pes_plot.png')
    os.remove('pes_plot.png')

    # Products should be made on this surface
    assert pes.products_made()

    # Get the TS guess from this surface calling all the above functions
    reactant = ReactantComplex(ch3cl_f)
    fbond = FormingBond(atom_indexes=(0, 2), species=reactant)
    fbond.final_dist = 1.5

    bbond = BreakingBond(atom_indexes=(1, 2),
                         species=reactant,
                         reaction=Reaction(ch3cl_f, ch3f_cl))
    bbond.final_dist = 4.0

    ts_guess = pes_2d.get_ts_guess_2d(reactant=reactant,
                                      product=ProductComplex(ch3f_cl),
                                      bond1=fbond,
                                      bond2=bbond,
                                      polynomial_order=3,
                                      name='SN2_PES',
                                      method=xtb,
                                      keywords=xtb.keywords.low_opt,
                                      dr=0.3)
    assert ts_guess is not None
    assert ts_guess.n_atoms == 6
    assert ts_guess.energy is None
    assert 1.9 < ts_guess.get_distance(0, 2) < 2.1
    assert 1.9 < ts_guess.get_distance(1, 2) < 2.0
예제 #20
0
# Override the availability of
orca.available = True
xtb.available = True

# Set the reactant and product complexes

h1 = Atom(atomic_symbol='H', x=0.0, y=0.0, z=0.0)
h2 = Atom(atomic_symbol='H', x=0.0, y=0.0, z=0.7)
h3 = Atom(atomic_symbol='H', x=0.0, y=0.0, z=1.7)

hydrogen = Molecule(name='H2', atoms=[h1, h2], charge=0, mult=1)
h = Molecule(name='H', atoms=[h3], charge=0, mult=2)

reac = ReactantComplex(hydrogen, h)
prod = ProductComplex(h, hydrogen)


def test_get_ts_guess_1dscan():
    os.chdir(os.path.join(here, 'data'))

    fbond = FormingBond(atom_indexes=(1, 2), species=reac)
    fbond.final_dist = 0.7

    ts_guess = get_ts_guess_1d(name='H+H2_H2+H',
                               reactant=reac,
                               product=prod,
                               bond=fbond,
                               method=orca,
                               keywords=opt_keywords,
                               dr=0.06)