def test_get_all_bespoke_smirks(): """ Generate bespoke smirks for all parameters in a molecule, make sure they all hit the intended atoms, and every term is now bespoke. """ gen = SmirksGenerator() gen.target_smirks = [ SmirksType.Vdw, SmirksType.Bonds, SmirksType.Angles, SmirksType.ProperTorsions ] mol = Molecule.from_smiles("CO") all_bespoke_smirks = gen._get_all_bespoke_smirks( molecule=mol, forcefield_editor=ForceFieldEditor( "openff_unconstrained-1.3.0.offxml")) # this is a list of all bespoke smirks with real initial values all_matches = [] for smirk in all_bespoke_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) assert compare_matches(atoms, smirk.atoms) is True all_matches.extend(atoms) assert all_covered(all_matches, mol) is True
def test_no_smirks_requested(): """ Make sure an error is raised if we try and generate smirks but do not request any smirks types. """ gen = SmirksGenerator() gen.target_smirks = [] mol = Molecule.from_smiles("CC") with pytest.raises(SMIRKSTypeError): gen.generate_smirks(molecule=mol)
def test_generate_smirks(bespoke_smirks): """ Test the main worker method to gather bespoke and non bespoke terms. """ gen = SmirksGenerator() gen.target_smirks = [ SmirksType.Vdw, ] gen.generate_bespoke_terms = bespoke_smirks mol = Molecule.from_smiles("CC") smirks_list = gen.generate_smirks(molecule=mol) # we only request one parameter type types = set([smirk.type for smirk in smirks_list]) assert len(types) == 1
def test_bespoke_target_torsion_smirks(): """ Generate bespoke torsion smirks only for the target torsions and make sure the intended atoms are covered. """ gen = SmirksGenerator() mol = Molecule.from_file(get_data("OCCO.sdf")) torsion_smirks = gen._get_bespoke_torsion_smirks(molecule=mol, central_bonds=[(1, 2)]) # there should be 3 unique smirks for this molecule # H-C-C-H, H-C-C-O, O-C-C-O assert len(torsion_smirks) == 3 for smirk in torsion_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) assert compare_matches(atoms, smirk.atoms) is True
def _generate_bespoke_torsions( self, forcefield: "ForceFieldEditor", parent_molecule: off.Molecule, task_data: TorsionTask, ) -> List[TorsionSmirks]: """ For the given task generate set of bespoke torsion terms for the parent molecule using all layers. Here we have to type the fragment and use the fragment parent mapping to transfer the parameters. """ from openff.bespokefit.smirks import SmirksGenerator smirks_gen = SmirksGenerator( target_smirks=[SmirksType.ProperTorsions], layers="all", expand_torsion_terms=False, ) fragment = task_data.graph_molecule fragment_parent_mapping = task_data.fragment_parent_mapping # label the fitting molecule labels = forcefield.label_molecule(molecule=fragment)["ProperTorsions"] bespoke_torsions = [] for bond in task_data.central_bonds: fragment_dihedrals = smirks_gen.get_all_torsions(bond=bond, molecule=fragment) for dihedral in fragment_dihedrals: # get the smirk that hit this torsion off_smirk = labels[dihedral] # work out the parent torsion parent_torsion = tuple( [fragment_parent_mapping[i] for i in dihedral]) # make the bespoke smirks smirks = smirks_gen._get_new_single_graph_smirks( atoms=parent_torsion, molecule=parent_molecule) # make the new Torsion Smirks bespoke_smirk = TorsionSmirks(smirks=smirks) bespoke_smirk.update_parameters(off_smirk=off_smirk) if bespoke_smirk not in bespoke_torsions: bespoke_torsions.append(bespoke_smirk) return bespoke_torsions
def test_bespoke_bond_smirks(): """ Make sure we can generate a bespoke bond smirks for each bond in a molecule and that every bond is covered. """ gen = SmirksGenerator() mol = Molecule.from_smiles("CC") bond_smirks = gen._get_bespoke_bond_smirks(molecule=mol) # there should be 2 unique bond smirks assert len(bond_smirks) == 2 all_bonds = [] for smirk in bond_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) all_bonds.extend(atoms) assert set(atoms) == smirk.atoms # make sure all bonds are covered for bond in mol.bonds: assert (bond.atom1_index, bond.atom2_index) in all_bonds
def _get_smirks_generator(self) -> SmirksGenerator: """ Build a smirks generator from the set of inputs. """ smirks_gen = SmirksGenerator( initial_forcefield=self.initial_forcefield, generate_bespoke_terms=self.generate_bespoke_terms, expand_torsion_terms=self.expand_torsion_terms, target_smirks=self.target_smirks, ) return smirks_gen
def test_bespoke_angle_smirks(): """ Make sure we can generate a bespoke angle smirks for each angle, also make sure the intended atoms are covered and that every angle has a bespoke smirks. """ gen = SmirksGenerator() mol = Molecule.from_smiles("CC") angle_smirks = gen._get_bespoke_angle_smirks(molecule=mol) # there should be 2 unique smirks assert len(angle_smirks) == 2 all_angles = [] for smirk in angle_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) all_angles.extend(atoms) assert set(atoms) == smirk.atoms # make sure all angles are covered for angle in mol.angles: assert tuple([atom.molecule_atom_index for atom in angle]) in all_angles
def test_bespoke_atom_smirks(): """ Make sure we can generate bespoke atom smirks for a molecule and that they cover the correct atoms, also check all atoms have a bespoke smirks. """ gen = SmirksGenerator() mol = Molecule.from_smiles("C") atom_smirks = gen._get_bespoke_atom_smirks(molecule=mol) # there should only be 2 unique smirks assert len(atom_smirks) == 2 # make sure the correct atoms are hit all_atoms = [] for smirk in atom_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) all_atoms.extend(atoms) assert set(atoms) == smirk.atoms # make sure all atoms have a bespoke smirks for i in range(mol.n_atoms): assert (i, ) in all_atoms
def test_bespoke_torsion_smirks(): """ Generate bespoke smirks for every torsion in the molecule, make sure that the intended atoms are covered and make sure every torsion has a bespoke smirks. """ gen = SmirksGenerator() mol = Molecule.from_file(get_data("OCCO.sdf")) torsion_smirks = gen._get_bespoke_torsion_smirks(molecule=mol) # there should be 5 unique torsions assert len(torsion_smirks) == 5 all_torsions = [] for smirk in torsion_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) all_torsions.extend(atoms) assert compare_matches(atoms, smirk.atoms) is True for torsion in mol.propers: dihedral = tuple([atom.molecule_atom_index for atom in torsion]) assert dihedral in all_torsions or tuple( reversed(dihedral)) in all_torsions
def test_get_all_smirks(): """ Get the full list of smirks which cover this molecule from the forcefield, no new smirks should be generated here. """ gen = SmirksGenerator() gen.target_smirks = [ SmirksType.Vdw, SmirksType.Bonds, SmirksType.Angles, SmirksType.ProperTorsions ] mol = Molecule.from_smiles("CO") all_smirks = gen._get_all_smirks(molecule=mol, forcefield_editor=ForceFieldEditor( "openff_unconstrained-1.3.0.offxml")) # this is a list of all of the smirks from the forcefield all_matches = [] for smirk in all_smirks: atoms = condense_matches(mol.chemical_environment_matches( smirk.smirks)) assert compare_matches(atoms, smirk.atoms) is True all_matches.extend(atoms) assert all_covered(all_matches, mol) is True
def target_dihedral(self) -> Tuple[int, int, int, int]: """ Return a target dihedral that could be driven for the target central bond. """ from openff.bespokefit.smirks import SmirksGenerator dihedrals = SmirksGenerator.get_all_torsions( bond=self.fragment_torsion, molecule=self.molecule) molecule = self.molecule # now find the first dihedral with no hydrogens, # if none can be found return any for dihedral in dihedrals: atoms = [molecule.atoms[i].atomic_number for i in dihedral] if 1 not in atoms: return dihedral return dihedrals[0]
def test_expand_torsion_terms(bespoke_smirks, expand_torsions): """ Make sure torsion terms are expanded up to 4 when requested for bespoke and standard smirks. """ gen = SmirksGenerator() gen.target_smirks = [ SmirksType.ProperTorsions, ] gen.generate_bespoke_terms = bespoke_smirks gen.expand_torsion_terms = expand_torsions mol = Molecule.from_smiles("CC") smirks_list = gen.generate_smirks(molecule=mol) # make sure there is only one parameter type types = set([smirk.type for smirk in smirks_list]) assert len(types) == 1 for smirk in smirks_list: if expand_torsions: assert len(smirk.terms) == 4 else: assert len(smirk.terms) < 4