def test_fix_stereo(smiles, fragment_smiles): parent_stereo = Fragmenter._find_stereo(smiles_to_molecule(smiles, True)) fragment = smiles_to_molecule(fragment_smiles, add_atom_map=True) fixed = Fragmenter._fix_stereo(fragment, parent_stereo) assert Fragmenter._check_stereo(fixed, parent_stereo) is True
def test_check_stereo(smiles, fragment_smiles, output, warning, caplog): parent = smiles_to_molecule(smiles, add_atom_map=True) fragment = smiles_to_molecule(fragment_smiles, add_atom_map=True) parent_stereo = Fragmenter._find_stereo(parent) with caplog.at_level(logging.WARNING): assert Fragmenter._check_stereo(fragment, parent_stereo) == output if warning is None: assert len(caplog.records) == 0 else: assert len(caplog.records) == 1 assert caplog.records[0].message.startswith(warning)
def test_cap_open_valance(): molecule, _, functional_groups, ring_systems = Fragmenter._prepare_molecule( smiles_to_molecule("CNCCc1ccccc1", True), default_functional_groups(), False) expected_atom = get_map_index( molecule, molecule.chemical_environment_matches("[#7]-[#6H3:1]")[0][0], ) # noinspection PyTypeChecker atoms, bonds = Fragmenter._get_torsion_quartet( molecule, tuple( get_map_index(molecule, i) for i in molecule.chemical_environment_matches("[#6a:1]-[#6H2:2]")[0]), ) atoms, bonds = Fragmenter._get_ring_and_fgroups(molecule, functional_groups, ring_systems, atoms, bonds) # Remove the cap atom from the current list to make sure it gets included during # capping. atoms -= {expected_atom} atoms, _ = Fragmenter._cap_open_valence(molecule, functional_groups, atoms, bonds) # Check that carbon bonded to N was added assert expected_atom in atoms
def test_get_ring_and_fgroup_ortho(input_smiles, bond_smarts, expected_pattern): """Ensure that FGs and rings attached to ortho groups are correctly detected. The expected values were generated using fragmenter=0.0.7 """ molecule, _, functional_groups, ring_systems = Fragmenter._prepare_molecule( smiles_to_molecule(input_smiles, True), default_functional_groups(), False) bond = tuple( get_map_index(molecule, i) for i in molecule.chemical_environment_matches(bond_smarts)[0]) # noinspection PyTypeChecker atoms, bonds = Fragmenter._get_torsion_quartet(molecule, bond) atoms, bonds = Fragmenter._get_ring_and_fgroups(molecule, functional_groups, ring_systems, atoms, bonds) actual_atoms = { map_index for map_index in atoms if molecule.atoms[get_atom_index(molecule, map_index)].atomic_number != 1 } expected_atoms = { get_map_index(molecule, atom_index) for match in molecule.chemical_environment_matches(expected_pattern) for atom_index in match } assert actual_atoms == expected_atoms
def test_atom_bond_set_to_mol(abemaciclib): molecule = smiles_to_molecule(abemaciclib.to_smiles(mapped=False), True) atoms = { get_map_index(molecule, atom_index) for match in molecule.chemical_environment_matches( "[C:1][C:2][N:3]1[C:4][C:5][N:6][C:7][C:8]1") for atom_index in match } bonds = {( get_map_index(molecule, bond.atom1_index), get_map_index(molecule, bond.atom2_index), ) for bond in molecule.bonds if get_map_index(molecule, bond.atom1_index) in atoms and get_map_index(molecule, bond.atom2_index) in atoms} fragment, _ = Fragmenter._atom_bond_set_to_mol(molecule, {}, atoms=atoms, bonds=bonds) for bond in fragment.bonds: if bond.atom1.atomic_number == 1 or bond.atom2.atomic_number == 1: continue map_index_1 = get_map_index(fragment, bond.atom1_index) map_index_2 = get_map_index(fragment, bond.atom2_index) assert tuple(sorted((map_index_1, map_index_2))) in bonds
def test_find_stereo(smiles, output): molecule = smiles_to_molecule(smiles, add_atom_map=True) actual_stereo = Fragmenter._find_stereo(molecule) expected_stereo = key_smarts_to_map_indices(output, molecule) assert actual_stereo == expected_stereo
def test_ring_fgroups(input_smiles, n_output): parent = smiles_to_molecule(input_smiles, True) parent_groups = Fragmenter._find_functional_groups( parent, default_functional_groups()) parent_rings = Fragmenter._find_ring_systems(parent, parent_groups) assert len(parent_rings[1][0]) == n_output
def test_keep_non_rotor(keep_non_rotor_ring_substituents, n_output): ring_systems = Fragmenter._find_ring_systems( smiles_to_molecule("c1ccccc1C", True), {}, keep_non_rotor_ring_substituents=keep_non_rotor_ring_substituents, ) assert len(ring_systems[1][0]) == n_output
def test_compare_wbo(): parent = assign_elf10_am1_bond_orders( smiles_to_molecule("CCCC", add_atom_map=True)) rotors_wbo = WBOFragmenter._get_rotor_wbo( parent, WBOFragmenter.find_rotatable_bonds(parent, None)) fragment = smiles_to_molecule("CCCC", add_atom_map=True) for bond_tuple, value in rotors_wbo.items(): assert numpy.isclose( WBOFragmenter._compare_wbo(fragment, bond_tuple, value), 0.0, atol=1.0e-6, ) assert numpy.isclose( WBOFragmenter._compare_wbo(fragment, bond_tuple, value + 1.0), 1.0, atol=1.0e-6, )
def test_get_torsion_quartet(input_smiles, expected_n_atoms, expected_n_bonds): molecule = smiles_to_molecule(input_smiles, True) bond_match = molecule.chemical_environment_matches("C[C:1][C:2]CCCC")[0] atoms, bonds = Fragmenter._get_torsion_quartet( molecule, ( get_map_index(molecule, bond_match[0]), get_map_index(molecule, bond_match[1]), ), ) # This also includes explicit hydrogen assert len(atoms) == expected_n_atoms assert len(bonds) == expected_n_bonds
def test_build_fragment(): parent = assign_elf10_am1_bond_orders(smiles_to_molecule("CCCCCC", True)) rotors_wbo = WBOFragmenter._get_rotor_wbo( parent, WBOFragmenter.find_rotatable_bonds(parent, None)) fragments = { bond: WBOFragmenter._build_fragment(parent, {}, {}, {}, bond, parent_wbo, threshold=0.05) for bond, parent_wbo in rotors_wbo.items() } assert len(fragments) == 3 assert (fragments[(3, 5)].to_smiles(explicit_hydrogens=False, mapped=False) == "CCCCC") assert (fragments[(4, 6)].to_smiles(explicit_hydrogens=False, mapped=False) == "CCCCC") assert (fragments[(5, 6)].to_smiles(explicit_hydrogens=False, mapped=False) == "CCCCCC")
def test_get_rotor_wbo(): molecule = smiles_to_molecule("CCCC", True) for bond in molecule.bonds: bond.fractional_bond_order = 0.986 expected_bonds = { ( get_map_index(molecule, match[0]), get_map_index(molecule, match[1]), ) for match in molecule.chemical_environment_matches("[#6:1]-[#6:2]") } rotors_wbo = WBOFragmenter._get_rotor_wbo( molecule, WBOFragmenter.find_rotatable_bonds(molecule, None)) assert len(rotors_wbo) == 1 rotor_index = next(iter(rotors_wbo)) assert rotor_index in expected_bonds assert numpy.isclose(rotors_wbo[rotor_index], 0.986, atol=0.001)
def test_get_ring_and_fgroup(input_smiles, bond_smarts, expected): molecule, _, functional_groups, ring_systems = Fragmenter._prepare_molecule( smiles_to_molecule(input_smiles, True), default_functional_groups(), False) # noinspection PyTypeChecker atoms, bonds = Fragmenter._get_torsion_quartet( molecule, tuple( get_map_index(molecule, i) for i in molecule.chemical_environment_matches(bond_smarts)[0]), ) bonds = {tuple(sorted(bond)) for bond in bonds} l_atoms = len(atoms) l_bonds = len(bonds) atoms_2, bonds_2 = Fragmenter._get_ring_and_fgroups( molecule, functional_groups, ring_systems, atoms, bonds) assert (l_atoms == len(atoms_2)) == expected assert (l_bonds == len(bonds_2)) == expected
def test_find_ring_systems(input_smiles, n_ring_systems): ring_systems = Fragmenter._find_ring_systems( smiles_to_molecule(input_smiles, True), {}) assert len(ring_systems) == n_ring_systems
def test_smiles_to_molecule(add_atom_map): molecule = smiles_to_molecule("CCCC", add_atom_map=add_atom_map) assert isinstance(molecule, Molecule) assert ("atom_map" in molecule.properties) == add_atom_map