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')
def test_one_to_three_dissociation(): r = Reactant(name='tet_int', smiles='CC(OS(Cl)=O)(Cl)O') p1 = Product(name='acyl', smiles='CC(Cl)=[OH+]') p2 = Product(name='so2', smiles='O=S=O') p3 = Product(name='chloride', smiles='[Cl-]') reaction = Reaction(r, p1, p2, p3, solvent_name='thf') assert reaction.type is Dissociation # Generate reactants and product complexes then find the single possible # bond rearrangement reactant, product = get_complexes(reaction) reaction.reactant, reaction.product = reactant, product bond_rearrangs = get_bond_rearrangs(reactant, product, name=str(reaction)) assert len(bond_rearrangs) == 1 os.remove(f'{str(reaction)}_bond_rearrangs.txt') # This dissociation breaks two bonds and forms none bond_rearrangement = bond_rearrangs[0] assert len(bond_rearrangement.fbonds) == 0 assert len(bond_rearrangement.bbonds) == 2 # Ensure there is at least one bond function that could give the TS ts_funcs_params = get_ts_guess_function_and_params(reaction, bond_rearrangement) assert len(list(ts_funcs_params)) > 0
def get_truncated_ts(reaction, bond_rearr): """Get the TS of a truncated reactant and product complex""" # Truncate the reactant and product complex to the core atoms so the full # TS can be template-d f_reactant = reaction.reactant.copy() f_product = reaction.product.copy() # Set the truncated reactant and product for this reaction reaction.reactant = get_truncated_complex(f_reactant, bond_rearr) reaction.product = get_truncated_complex(f_product, bond_rearr) # Re-find the bond rearrangements, which should exist reaction.name += '_truncated' bond_rearrangs = get_bond_rearrangs(reaction.reactant, reaction.product, name=reaction.name) if bond_rearrangs is None: logger.error('Truncation generated a complex with 0 rearrangements') return None # Find all the possible TSs for bond_rearr in bond_rearrangs: get_ts(reaction, reaction.reactant, bond_rearr, is_truncated=True) # Reset the reactant, product and name of the full reaction reaction.reactant = f_reactant reaction.product = f_product reaction.name = reaction.name.rstrip('_truncated') logger.info('Done with truncation') return None
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
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)])]
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')
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
def test_detection(): # F- + H2CCHCH2Cl -> FCH2CHCH2 + Cl- reaction = Reaction(Reactant(name='F-', charge=-1, atoms=[Atom('F')]), Reactant(name='alkeneCl', smiles='C=CCCl'), Product(name='alkeneF', smiles='C=CCF'), Product(name='Cl-', charge=-1, atoms=[Atom('Cl')])) assert reaction.type == Substitution reactant, product = get_complexes(reaction) bond_rearrs = get_bond_rearrangs(reactant, product, name='SN2') # autodE should find both direct SN2 and SN2' pathways assert len(bond_rearrs) == 2 os.remove('SN2_bond_rearrangs.txt')
def test_prune_small_rings2(): reaction = ade.Reaction('CCCC=C>>C=C.C=CC') reaction.find_complexes() ade.Config.skip_small_ring_tss = False bond_rearrs = br.get_bond_rearrangs(reactant=reaction.reactant, product=reaction.product, name='tmp', save=False) assert len(bond_rearrs) > 2 ade.Config.skip_small_ring_tss = True br.prune_small_ring_rearrs(bond_rearrs, reaction.reactant) assert len(bond_rearrs) == 2 # Should find the 6-membered TS assert (bond_rearrs[0].n_membered_rings(reaction.reactant) == [6] or bond_rearrs[1].n_membered_rings(reaction.reactant) == [6])
def find_tss(reaction): """Find all the possible the transition states of a reaction Arguments: reaction (list(autode.reaction.Reaction)): Reaction Returns: list: list of transition state objects """ logger.info('Finding possible transition states') reactant, product = reaction.reactant, reaction.product if species_are_isomorphic(reactant, product): logger.error('Reactant and product complexes are isomorphic. Cannot' ' find a TS') return None bond_rearrs = get_bond_rearrangs(reactant, product, name=str(reaction)) if bond_rearrs is None: logger.error('Could not find a set of forming/breaking bonds') return None tss = [] for bond_rearrangement in bond_rearrs: logger.info(f'Locating transition state using active bonds ' f'{bond_rearrangement.all}') ts = get_ts(reaction, reactant, bond_rearrangement) if ts is not None: tss.append(ts) if len(tss) == 0: logger.error('Did not find any transition state(s)') return None logger.info( f'Found *{len(tss)}* transition state(s) that lead to products') return tss