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
def test_2b2f(): reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 0.6, 0, 0), Atom('N', 10, 0, 0), Atom('O', 10.6, 0, 0)]) prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 10, 0, 0), Atom('N', 0.6, 0, 0), Atom('O', 10.6, 0, 0)]) assert br.get_fbonds_bbonds_2b2f(reac, prod, [], [[(0, 1)], [(2, 3)]], [[(0, 2)], [(1, 3)]], [], [], []) == [ br.BondRearrangement(forming_bonds=[(0, 2), (1, 3)], breaking_bonds=[(0, 1), (2, 3)])] reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 0.6, 0, 0), Atom('H', 10, 0, 0), Atom('N', 10.6, 0, 0), Atom('O', 20, 0, 0)]) prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 10, 0, 0), Atom('H', 1.2, 0, 0), Atom('N', 20, 0, 0), Atom('O', 0.6, 0, 0)]) assert br.get_fbonds_bbonds_2b2f(reac, prod, [], [[(0, 1)], [(2, 3)]], [[(0, 4), (2, 4)]], [], [], []) == [ br.BondRearrangement(forming_bonds=[(0, 4), (2, 4)], breaking_bonds=[(0, 1), (2, 3)])] reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 0.6, 0, 0), Atom('H', 1.2, 0, 0), Atom('O', 10, 0, 0)]) prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 10, 0, 0), Atom('H', 11.2, 0, 0), Atom('O', 10.6, 0, 0)]) assert br.get_fbonds_bbonds_2b2f(reac, prod, [], [[(0, 1), (1, 2)]], [[(0, 3), (2, 3)], [(1, 3)]], [], [], []) == [ br.BondRearrangement(forming_bonds=[(0, 3), (1, 3)], breaking_bonds=[(0, 1), (1, 2)]), br.BondRearrangement(forming_bonds=[(1, 3), (2, 3)], breaking_bonds=[(0, 1), (1, 2)])] reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 0.6, 0, 0), Atom('H', 1.2, 0, 0), Atom('O', 10, 0, 0)]) prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 10, 0, 0), Atom('H', 1.2, 0, 0), Atom('O', 0.6, 0, 0)]) assert br.get_fbonds_bbonds_2b2f(reac, prod, [], [[(0, 1), (1, 2)]], [[(0, 3), (2, 3)]], [], [], []) == [ br.BondRearrangement(forming_bonds=[(0, 3), (2, 3)], breaking_bonds=[(0, 1), (1, 2)])] reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 0.6, 0, 0), Atom('N', 1.2, 0, 0), Atom('C', 10, 0, 0)]) prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('C', 10, 0, 0), Atom('N', 1.2, 0, 0), Atom('C', 0.6, 0, 0)]) assert br.get_fbonds_bbonds_2b2f(reac, prod, [], [], [], [[[(0, 1)], [(0, 3)]], [[(1, 2)], [(2, 3)]]], [], []) == [br.BondRearrangement(forming_bonds=[(0, 3), (2, 3)], breaking_bonds=[(0, 1), (1, 2)])]
def test_butene(tmpdir): os.chdir(tmpdir) butene = Molecule(name='z-but-2-ene', charge=0, mult=1, atoms=[ Atom('C', -1.69185, -0.28379, -0.01192), Atom('C', -0.35502, -0.40751, 0.01672), Atom('C', -2.39437, 1.04266, -0.03290), Atom('H', -2.13824, 1.62497, 0.87700), Atom('H', -3.49272, 0.88343, -0.05542), Atom('H', -2.09982, 1.61679, -0.93634), Atom('C', 0.57915, 0.76747, 0.03048), Atom('H', 0.43383, 1.38170, -0.88288), Atom('H', 1.62959, 0.40938, 0.05452), Atom('H', 0.39550, 1.39110, 0.93046), Atom('H', -2.29700, -1.18572, -0.02030), Atom('H', 0.07422, -1.40516, 0.03058) ]) butene.graph.nodes[0]['stereo'] = True butene.graph.nodes[1]['stereo'] = True # Conformer generation should retain the stereochemistry atoms = conf_gen.get_simanl_atoms(species=butene) regen = Molecule(name='regenerated_butene', atoms=atoms, charge=0, mult=1) regen.print_xyz_file() regen_coords = regen.coordinates # The Z-butene isomer has a r(C_1 C_2) < 3.2 Å where C_1C=CC_2 assert np.linalg.norm(regen_coords[6] - regen_coords[2]) < 3.6 os.chdir(here)
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 get_optimised_species(calc, method, direction, atoms): """Get the species that is optimised from an initial set of atoms""" species = Molecule(name=f'{calc.name}_{direction}', atoms=atoms, charge=calc.molecule.charge, mult=calc.molecule.mult) # Note that for the surface to be the same the keywords.opt and keywords.hess need to match in the level of theory calc = Calculation(name=f'{calc.name}_{direction}', molecule=species, method=method, keywords=method.keywords.opt, n_cores=Config.n_cores) calc.run() try: species.set_atoms(atoms=calc.get_final_atoms()) species.energy = calc.get_energy() make_graph(species) except AtomsNotFound: logger.error(f'{direction} displacement calculation failed') return species
def test_grad(): h2 = Molecule(name='h2', atoms=[Atom('H'), Atom('H', x=0.5)]) grad_calc = Calculation(name='h2_grad', molecule=h2, method=method, keywords=Config.MOPAC.keywords.grad) grad_calc.run() energy = grad_calc.get_energy() assert energy is not None gradients = grad_calc.get_gradients() assert gradients.shape == (2, 3) delta_r = 1E-5 h2_disp = Molecule(name='h2_disp', atoms=[Atom('H'), Atom('H', x=0.5 + delta_r)]) h2_disp.single_point(method) delta_energy = h2_disp.energy - energy # Ha] grad = delta_energy / delta_r # Ha A^-1 # Difference between the absolute and finite difference approximation assert np.abs(gradients[1, 0] - grad) < 1E-1 # Broken gradient file grad_calc.output.filename = 'h2_grad_broken.out' grad_calc.output.file_lines = open('h2_grad_broken.out', 'r').readlines() with pytest.raises(CouldNotGetProperty): _ = grad_calc.get_gradients()
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_1b1f(): reac = Molecule(atoms=[Atom('C', 0, 0, 0), Atom('H', 0.6, 0, 0), Atom('H', 10, 0, 0)]) prod = Molecule(atoms=[Atom('C', 0, 0, 0), Atom('H', 10, 0, 0), Atom('H', 10.6, 0, 0)]) assert br.get_fbonds_bbonds_1b1f(reac, prod, [], [[(0, 1)]], [[(1, 2)]], [], [], []) == [br.BondRearrangement(forming_bonds=[(1, 2)], breaking_bonds=[(0, 1)])] reac = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('H', 0.6, 0, 0), Atom('H', 10, 0, 0)]) prod = Molecule(atoms=[Atom('H', 0, 0, 0), Atom('H', 10, 0, 0), Atom('H', 10.6, 0, 0)]) assert br.get_fbonds_bbonds_1b1f(reac, prod, [], [], [], [[[(0, 1)], [(1, 2)]]], [], []) == [br.BondRearrangement(forming_bonds=[(1, 2)], breaking_bonds=[(0, 1)])]
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)
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_molecule_from_xyz(): os.chdir(os.path.join(here, 'data')) h2 = Molecule('h2_conf0.xyz') assert h2.name == 'h2_conf0' assert h2.n_atoms == 2 assert h2.formula() == 'H2' os.chdir(here)
def test_siman_conf_gen(tmpdir): os.chdir(tmpdir) rh_complex = Molecule(name='[RhH(CO)3(ethene)]', smiles='O=C=[Rh]1(=C=O)(CC1)([H])=C=O') assert are_coords_reasonable(coords=rh_complex.get_coordinates()) assert rh_complex.n_atoms == 14 assert 12 < rh_complex.graph.number_of_edges() < 15 # What is a bond even os.chdir(here)
def test_metal_eta_complex(tmpdir): os.chdir(tmpdir) # eta-6 benzene Fe2+ complex used in the molassembler paper m = Molecule(smiles='[C@@H]12[C@H]3[C@H]4[C@H]5[C@H]6[C@@H]1[Fe]265437N' '(C8=CC=CC=C8)C=CC=[N+]7C9=CC=CC=C9') m.print_xyz_file() assert are_coords_reasonable(coords=m.get_coordinates()) os.chdir(here)
def calc_mult(): h = Molecule(name='H', smiles='[H]') assert calc_multiplicity(h, n_radical_electrons=1) == 2 # Setting the multiplicity manually should override the number of radical electrons derived from the SMILES string # note: H with M=3 is obviously not possible h.mult = 3 assert calc_multiplicity(h, n_radical_electrons=1) == 3 # Diradicals should default to singlets.. assert calc_multiplicity(h, n_radical_electrons=2) == 1
def test_find_lowest_energy_conformer(): # Spoof XTB availability xtb.path = here propane = Molecule(name='propane', smiles='CCC') propane.find_lowest_energy_conformer(lmethod=xtb) assert len(propane.conformers) > 0 # Finding low energy conformers should set the energy of propane assert propane.energy is not None assert propane.atoms is not None
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_molecule_opt(): mol = Molecule(name='H2', smiles='[H][H]') # Set the orca path to something that exists orca.path = here mol.optimise(method=orca) assert mol.energy == -1.160687049941 assert mol.n_atoms == 2 opt_coords = mol.get_coordinates() # H2 bond length ~ 0.767 Å at PBE/def2-SVP assert 0.766 < np.linalg.norm(opt_coords[0] - opt_coords[1]) < 0.768
def test_gradients(): os.chdir(os.path.join(here, 'data', 'xtb')) h2 = Molecule(name='h2', atoms=[Atom('H'), Atom('H', x=1.0)]) h2.single_point(method) delta_r = 1E-5 h2_disp = Molecule(name='h2_disp', atoms=[Atom('H'), Atom('H', x=1.0 + delta_r)]) h2_disp.single_point(method) delta_energy = h2_disp.energy - h2.energy # Ha grad = delta_energy / delta_r # Ha A^-1 calc = Calculation(name='h2_grad', molecule=h2, method=method, keywords=method.keywords.grad) calc.run() diff = calc.get_gradients()[1, 0] - grad # Ha A^-1 # Difference between the absolute and finite difference approximation assert np.abs(diff) < 1E-5 # Older xtb version with open('gradient', 'w') as gradient_file: print( '$gradient\n' 'cycle = 1 SCF energy = -4.17404780397 |dE/dxyz| = 0.027866\n' '3.63797523123375 -1.13138130908142 -0.00032759661848 C \n' '5.72449332438353 -1.13197561185651 0.00028950521969 H \n' ' 2.94133258016711 0.22776472016180 -1.42078243039077 H \n' ' 2.94175598539510 -0.58111835182372 1.88747566982948 H \n' '2.94180792167968 -3.04156357656436 -0.46665514803992 H \n' '-1.7221823521705E-05 7.9930724499610E-05 -1.1737079840097E-04\n' ' 1.4116296505865E-02 -4.0359524399270E-05 3.9719638516747E-05\n' '-4.7199424681741E-03 9.0086220034949E-03 -9.4114548523723E-03\n' '-4.6956970257351E-03 3.6356853660431E-03 1.2558467871909E-02\n' ' -4.6834351884340E-03 -1.2683878569638E-02 -3.0693618596526E-03\n' '$end', file=gradient_file) calc = Calculation(name='methane', molecule=Molecule(name='methane', smiles='C'), method=method, keywords=method.keywords.grad) gradients = method.get_gradients(calc) assert gradients.shape == (5, 3) assert np.abs(gradients[0, 0]) < 1E-3 os.chdir(here)
def test_fix_angle_error(): os.chdir(os.path.join(here, 'data', 'g09')) mol = Molecule(smiles='CC/C=C/CO') mol.name = 'molecule' calc = Calculation(name='angle_fail', molecule=mol, method=method, keywords=opt_keywords) calc.run() assert os.path.exists('angle_fail_g09_cartesian.com') is True assert os.path.exists('angle_fail_g09_internal.com') is True assert calc.output.filename == 'angle_fail_g09_internal.log' assert calc.terminated_normally()
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_conformers(): methane = Molecule(name='methane', smiles='C') # Function requiring a molecule having a conformer attribute @utils.requires_conformers() def test(mol): print(mol.conformers[0].n_atoms) with pytest.raises(NoConformers): test(methane) # Populating a species conformers should allow this function to be called methane.conformers = [Conformer(name='conf0', atoms=methane.atoms)] test(methane)
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)
def test_psi4_opt_calculation(): methylchloride = Molecule(name='CH3Cl', smiles='[H]C([H])(Cl)[H]', solvent_name='water') calc = Calculation(name='opt', molecule=methylchloride, method=method, keywords=opt_keywords) calc.run() assert os.path.exists('opt_psi4.inp') is True assert os.path.exists('opt_orca.out') is True assert len(calc.get_final_atoms()) == 5 assert -499.735 < calc.get_energy() < -499.730 assert calc.output.exists() assert calc.output.file_lines is not None assert calc.get_imaginary_freqs() == [] assert calc.input.filename == 'opt_psi4.inp' assert calc.output.filename == 'opt_psi4.out' assert calc.terminated_normally() assert calc.optimisation_converged() calc = Calculation(name='opt', molecule=methylchloride, method=method, keywords=opt_keywords) # If the calculation is not run with calc.run() then there should be no # input and the calc should raise that there is no input with pytest.raises(NoInputError): execute_calc(calc)
def test_calc_bad_mol(): class Mol: pass mol = Mol() with pytest.raises(AssertionError): Calculation(name='bad_mol_object', molecule=mol, method=method, keywords=opt_keywords) mol.atoms = None mol.mult = 1 mol.n_atoms = 0 mol.charge = 0 mol.solvent = None with pytest.raises(NoInputError): Calculation(name='no_atoms_mol', molecule=mol, method=method, keywords=opt_keywords) mol = Molecule(name='methane', smiles='C') mol.solvent = Solvent(name='xx', smiles='X', aliases=['X']) with pytest.raises(SolventUnavailable): Calculation(name='no_atoms_mol', molecule=mol, method=method, keywords=opt_keywords)
def test_solvation(): methane = Molecule(name='solvated_methane', smiles='C', solvent_name='water') with pytest.raises(UnsuppportedCalculationInput): # Should raise on unsupported calculation type method.implicit_solvation_type = 'xxx' calc = Calculation(name='broken_solvation', molecule=methane, method=method, keywords=sp_keywords) calc.run() method.implicit_solvation_type = 'CPCM' calc = Calculation(name='methane_cpcm', molecule=methane, method=method, keywords=sp_keywords) calc.generate_input() assert any('cpcm' in line.lower() for line in open('methane_cpcm_orca.inp', 'r')) os.remove('methane_cpcm_orca.inp') method.implicit_solvation_type = 'SMD' calc = Calculation(name='methane_smd', molecule=methane, method=method, keywords=sp_keywords) calc.generate_input() assert any('smd' in line.lower() for line in open('methane_smd_orca.inp', 'r')) os.remove('methane_smd_orca.inp')
def test_graph_without_active_edges(): mol = Molecule(name='H2', atoms=[Atom('H'), Atom('H', x=0.7)]) mol.graph.edges[(0, 1)]['active'] = True graph = mol_graphs.get_graph_no_active_edges(mol.graph) # Should now have no edges if the one bond was defined as active assert graph.number_of_edges() == 0
def test_chiral_rotation(tmpdir): os.chdir(tmpdir) chiral_ethane = Molecule(name='chiral_ethane', charge=0, mult=1, atoms=[ Atom('C', -0.26307, 0.59858, -0.07141), Atom('C', 1.26597, 0.60740, -0.09729), Atom('Cl', -0.91282, 2.25811, 0.01409), Atom('F', -0.72365, -0.12709, 1.01313), Atom('H', -0.64392, 0.13084, -1.00380), Atom('Cl', 1.93888, 1.31880, 1.39553), Atom('H', 1.61975, 1.19877, -0.96823), Atom('Br', 1.94229, -1.20011, -0.28203) ]) chiral_ethane.graph.nodes[0]['stereo'] = True chiral_ethane.graph.nodes[1]['stereo'] = True atoms = conf_gen.get_simanl_atoms(chiral_ethane) regen = Molecule(name='regenerated_ethane', charge=0, mult=1, atoms=atoms) regen_coords = regen.coordinates coords = chiral_ethane.coordinates # Atom indexes of the C(C)(Cl)(F)(H) chiral centre ccclfh = [0, 1, 2, 3, 4] # Atom indexes of the C(C)(Cl)(Br)(H) chiral centre ccclbrh = [1, 0, 5, 7, 6] for centre_idxs in [ccclfh, ccclbrh]: # Ensure the fragmented centres map almost identically # if calc_rmsd(template_coords=coords[centre_idxs], coords_to_ # fit=regen_coords[centre_idxs]) > 0.5: # chiral_ethane.print_xyz_file(filename=os.path.join(here, # 'chiral_ethane.xyz')) # regen.print_xyz_file(filename=os.path.join(here, 'regen.xyz')) # RMSD on the 5 atoms should be < 0.5 Å assert calc_rmsd(coords1=coords[centre_idxs], coords2=regen_coords[centre_idxs]) < 0.5 os.chdir(here)
def test_nci_complex(): water = Molecule(name='water', smiles='O') f = Molecule(name='formaldehyde', smiles='C=O') nci_complex = NCIComplex(f, water) assert nci_complex.n_atoms == 7 # Set so the number of conformers doesn't explode Config.num_complex_sphere_points = 6 Config.num_complex_random_rotations = 4 nci_complex._generate_conformers() assert len(nci_complex.conformers) == 24 for conformer in nci_complex.conformers: # conformer.print_xyz_file() assert geom.are_coords_reasonable(coords=conformer.get_coordinates())
def test_basic_attributes(): with pytest.raises(NoAtomsInMolecule): Molecule(atoms=[]) Molecule() methane = Molecule(name='methane', smiles='C') assert methane.name == 'methane' assert methane.smiles == 'C' assert methane.energy is None assert methane.n_atoms == 5 assert methane.graph.number_of_edges() == 4 assert methane.graph.number_of_nodes() == methane.n_atoms assert methane.conformers is None assert methane.charge == 0 assert methane.mult == 1 assert isinstance(methane.rdkit_mol_obj, Mol)
def test_find_lowest_energy_conformer(): os.chdir(os.path.join(here, 'data')) # Spoof XTB availability xtb.path = here xtb.available = True propane = Molecule(name='propane', smiles='CCC') propane.find_lowest_energy_conformer(lmethod=xtb) assert len(propane.conformers) > 0 # Finding low energy conformers should set the energy of propane assert propane.energy is not None assert propane.atoms is not None os.chdir(here)