def test_molecule_tag_assignment(self): """ It tests the molecule tag assignment. """ # Look for UNK tag when dummy Molecule is loaded molecule = Molecule() assert molecule.tag == 'UNK', 'Unexpected atom tag' # Look for the PDB residue name as a tag when a Molecule is loaded # from a PDB file ligand_path = get_data_file_path('ligands/BNZ.pdb') molecule = Molecule(ligand_path) assert molecule.tag == 'BNZ', 'Unexpected atom tag' # Look for BEN tag when a Molecule is loaded from a PDB file with # a custom name ligand_path = get_data_file_path('ligands/BNZ.pdb') molecule = Molecule(ligand_path, tag='BEN') assert molecule.tag == 'BEN', 'Unexpected atom tag' # Look for UNK tag when a Molecule is loaded from a SMILES tag molecule = Molecule(smiles='c1ccccc1') assert molecule.tag == 'UNK', 'Unexpected atom tag' # Look for BNZ tag when a Molecule is loaded from a SMILES tag with # a custom tag molecule = Molecule(smiles='c1ccccc1', tag='BNZ') assert molecule.tag == 'BNZ', 'Unexpected atom tag'
def test_molecule_name_assignment(self): """ It tests the molecule name assignment. """ # Look for an empty name when dummy Molecule is loaded molecule = Molecule() assert molecule.name == '', 'Unexpected atom name' # Look for the PDB name when a Molecule is loaded from a PDB file ligand_path = get_data_file_path('ligands/BNZ.pdb') molecule = Molecule(ligand_path) assert molecule.name == 'BNZ', 'Unexpected atom name' # Look for benzene name when a Molecule is loaded from a PDB file # with a custom name ligand_path = get_data_file_path('ligands/BNZ.pdb') molecule = Molecule(ligand_path, name='benzene') assert molecule.name == 'benzene', 'Unexpected atom name' # Look for the SMILES name when a Molecule is loaded from a SMILES tag molecule = Molecule(smiles='c1ccccc1') assert molecule.name == 'c1ccccc1', 'Unexpected atom name' # Look for benzene name when a Molecule is loaded from a SMILES tag # with a custom name molecule = Molecule(smiles='c1ccccc1', name='benzene') assert molecule.name == 'benzene', 'Unexpected atom name'
def test_bad_init_parameterization(self): """ It checks that a call to the parameterize function with a Molecule unsuccessfully initialized raises an Exception. """ FORCEFIELD_NAME = 'openff_unconstrained-1.1.1.offxml' LIGAND_PATH = SET_OF_LIGAND_PATHS[0] ligand_path = get_data_file_path(LIGAND_PATH) molecule = Molecule() with pytest.raises(Exception): molecule.parameterize(FORCEFIELD_NAME) rdkit_toolkit = RDKitToolkitWrapper() molecule._rdkit_molecule = rdkit_toolkit.from_pdb(ligand_path) molecule._off_molecule = None with pytest.raises(Exception): molecule.parameterize(FORCEFIELD_NAME) openforcefield_toolkit = OpenForceFieldToolkitWrapper() molecule._off_molecule = openforcefield_toolkit.from_rdkit(molecule) molecule._rdkit_molecule = None with pytest.raises(Exception): molecule.parameterize(FORCEFIELD_NAME)
class OBC1(_SolventWrapper): """ Implementation of the OBC1 solvent. """ _ff_file = get_data_file_path('forcefields/GBSA_OBC1-1.0.offxml') _name = 'OBC1' def __init__(self, molecule): """ Initializes an OBC1 object. Parameters ---------- molecule : An offpele.topology.Molecule A Molecule object to be written as an Impact file """ # Not implemented in PELE import warnings warnings.formatwarning = warning_on_one_line warnings.warn("OBC1 is not implemented in PELE", Warning) super().__init__(molecule) def _initialize_from_molecule(self): """ Initializes the OBC1 solvent using an offpele's Molecule. """ super()._initialize_from_molecule()
def test_OPLS_method(self): """It tests the OPLS method""" ligand_path = get_data_file_path(self.LIGAND_PATH) molecule = Molecule(ligand_path) # To avoid the use of Schrodinger Toolkit charges = [-0.22, 0.7, -0.12, -0.8, -0.8, -0.12, -0.12, -0.12, -0.12, -0.12, -0.115, -0.115, -0.12, -0.12, -0.12, -0.12, -0.12, -0.12, -0.12, -0.18, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.115, 0.115, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06] molecule._OPLS_parameters = SchrodingerToolkitWrapper.OPLSParameters( {'charges': [unit.Quantity(charge, unit.elementary_charge) for charge in charges]}) molecule.parameterize(FORCEFIELD_NAME, charges_method='OPLS') assert len(molecule.off_molecule.partial_charges) == len(charges), \ 'Size of Molecule\'s partial charges is expected to match ' \ + 'with size of reference charges list' for charge, expected_charge in zip( molecule.off_molecule.partial_charges, charges): assert charge == unit.Quantity(expected_charge, unit.elementary_charge), \ 'Unexpected charge {}'.format(charge)
def test_gasteiger_method(self): """It tests the gasteiger method""" ligand_path = get_data_file_path(self.LIGAND_PATH) molecule = Molecule(ligand_path) molecule.parameterize(FORCEFIELD_NAME, charges_method='gasteiger') check_CHO_charges_in_molecule(molecule)
def test_offpele_default_call(self): LIGAND_PATH = 'ligands/BNZ.pdb' ligand_path = get_data_file_path(LIGAND_PATH) with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): run_offpele(ligand_path, output=tmpdir)
def _add_solvent_parameters(self, OPLS_params): """ It add the solvent parameters to the OPLS parameters collection. Parameters ---------- OPLS_params : an OPLSParameters object The set of lists of parameters grouped by parameter type. Thus, the dictionary has the following keys: atom_names, atom_types, charges, sigmas, and epsilons. The following solvent parameters will be added to the collection: SGB_radii, vdW_radii, gammas, alphas """ solvent_data = dict() parameters_path = get_data_file_path('parameters/f14_sgbnp.param') with open(parameters_path) as f: for line in f: if line.startswith('#'): continue fields = line.split() assert len(fields) > 7, 'Unexpected line with less than ' \ '8 fields at {}'.format(line) atom_type = fields[1] solvent_data[atom_type] = { 'SGB_radii': unit.Quantity(float(fields[4]), unit.angstrom), 'vdW_radii': unit.Quantity(float(fields[5]), unit.angstrom), 'gammas': float(fields[6]), 'alphas': float(fields[7]) } parameters_to_add = defaultdict(list) tried = list() for atom_type in OPLS_params['atom_types']: parameters_found = False while (not parameters_found): if atom_type in solvent_data: for label, value in solvent_data[atom_type].items(): parameters_to_add[label].append(value) parameters_found = True else: new_atom_type = self._find_similar_atom_types( atom_type, tried) if new_atom_type is None: atom_type = 'DF' # Set it to default else: tried.append(new_atom_type) atom_type = new_atom_type for label, params in parameters_to_add.items(): OPLS_params.add_parameters(label, params)
def test_offpele_default_call(self): """ It checks the default call of offpele's main function. """ LIGAND_PATH = 'ligands/BNZ.pdb' ligand_path = get_data_file_path(LIGAND_PATH) with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): run_offpele(ligand_path, output=tmpdir)
def test_PDB_residue_name(self): """ It tests the PDB residue name and checks for consistency with Molecule tag. """ def check_residue_name(name): """Check if residue names are valid in the output PDB file""" with open('molecule.pdb') as f: for line in f: if line.startswith('HETATM'): assert line[17:20] == name, 'Unexpected residue name' ligand_path = get_data_file_path('ligands/BNZ.pdb') # Checking tag assignation from PDB molecule = Molecule(ligand_path) with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): assert molecule.tag == 'BNZ', 'Unexpected molecule tag' molecule.to_pdb_file('molecule.pdb') check_residue_name('BNZ') # Checking set_tag() function molecule = Molecule(ligand_path) with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): molecule.set_tag('TAG') assert molecule.tag == 'TAG', 'Unexpected molecule tag' molecule.to_pdb_file('molecule.pdb') check_residue_name('TAG') # Checking default tag assignment from SMILES molecule = Molecule(smiles='c1ccccc1') with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): assert molecule.tag == 'UNK', 'Unexpected molecule tag' molecule.to_pdb_file('molecule.pdb') check_residue_name('UNK') # Checking custom tag assignment from SMILES molecule = Molecule(smiles='c1ccccc1', tag='BEN') with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): assert molecule.tag == 'BEN', 'Unexpected molecule tag' molecule.to_pdb_file('molecule.pdb') check_residue_name('BEN') # Checking second custom tag assignment from SMILES molecule = Molecule(smiles='c1ccccc1') with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): molecule.set_tag('BNZ') assert molecule.tag == 'BNZ', 'Unexpected molecule tag' molecule.to_pdb_file('molecule.pdb') check_residue_name('BNZ')
def test_good_init_parameterization(self): """ It checks that a call to the parameterize function with a Molecule successfully initialized does not raise any Exception. """ FORCEFIELD_NAME = 'openff_unconstrained-1.1.1.offxml' LIGAND_PATH = SET_OF_LIGAND_PATHS[0] ligand_path = get_data_file_path(LIGAND_PATH) molecule = Molecule(ligand_path) molecule.parameterize(FORCEFIELD_NAME)
def test_offpele_custom_call(self): LIGAND_PATH = 'ligands/BNZ.pdb' ligand_path = get_data_file_path(LIGAND_PATH) with tempfile.TemporaryDirectory() as tmpdir: with temporary_cd(tmpdir): run_offpele(ligand_path, forcefield=FORCEFIELD_NAME, resolution=10, charges_method='gasteiger', output=tmpdir, with_solvent=True, as_datalocal=True)
def _find_similar_atom_types(self, atom_type, tried): """ It tries to find a similar atom type, skipping the ones that have already been tried. It uses the definitions from the similarity.param file. Parameters ---------- atom_type : str The atom type from which similar atom types will be searched tried : list[str] The list of atom types that have already been tried and will be skipped Returns ------- new_atom_type : str The most similar atom type that has been found, if any. Otherwise, it returns None """ new_atom_type = None best_similarity = 0 similarity_path = get_data_file_path('parameters/similarity.param') with open(similarity_path) as f: for line in f: fields = line.split() assert len(fields) > 2, 'Unexpected number of fields at ' \ + 'line {}'.format(line) atom_type1, atom_type2, similarity = fields[0:3] if (atom_type == atom_type1 and float(similarity) > best_similarity and atom_type2 not in tried): best_similarity = float(similarity) new_atom_type = atom_type2 elif (atom_type == atom_type2 and float(similarity) > best_similarity and atom_type1 not in tried): best_similarity = float(similarity) new_atom_type = atom_type1 return new_atom_type
def test_OFF_to_PELE_conversion(self): """ It checks the difference between dihedral equations from PELE and Open Force Field. Their values should match throughout all the domain. """ MAX_THRESHOLD = 1e-10 for ligand_path in SET_OF_LIGAND_PATHS: ligand_path = get_data_file_path(ligand_path) molecule = Molecule(ligand_path) molecule.parameterize(FORCEFIELD_NAME, charges_method='gasteiger') x = unit.Quantity(np.arange(0, np.pi, 0.1), unit=unit.radians) for PELE_proper, OFF_proper in zip(molecule.propers, molecule._OFF_propers): PELE_y = apply_PELE_dihedral_equation(PELE_proper, x) OFF_y = apply_OFF_dihedral_equation(OFF_proper, x) y_diff = PELE_y - OFF_y assert np.linalg.norm(y_diff) < MAX_THRESHOLD
class OBC2(_SolventWrapper): """ Implementation of the OBC2 solvent. """ _ff_file = get_data_file_path('forcefields/GBSA_OBC2-1.0.offxml') _name = 'OBC2' def __init__(self, molecule): """ Initializes an OBC2 object. Parameters ---------- molecule : An offpele.topology.Molecule A Molecule object to be written as an Impact file Examples -------- Generate the solvent parameters of a molecule >>> from offpele.topology import Molecule >>> from offpele.solvent import OBC2 >>> molecule = Molecule('molecule.pdb') >>> solvent = OBC2(molecule) >>> solvent.to_json_file('molecule_solv.json') """ super().__init__(molecule) def _initialize_from_molecule(self): """ Initializes the OBC2 solvent using an offpele's Molecule. """ super()._initialize_from_molecule()
def test_terminal_rotamer_filtering(self): """ It tests the rotamer library builder when the terminal rotatable bonds are ignored. """ LIGAND_PATH = 'ligands/OLC.pdb' ligand_path = get_data_file_path(LIGAND_PATH) molecule = Molecule(ligand_path, exclude_terminal_rotamers=True) rotamers_per_branch = molecule.rotamers assert len(rotamers_per_branch) == 2, "Found an invalid number " + \ "of branches: {}".format(len(rotamers_per_branch)) atom_list_1 = list() atom_list_2 = list() rotamers = rotamers_per_branch[0] for rotamer in rotamers: atom_list_1.append(set([rotamer.index1, rotamer.index2])) rotamers = rotamers_per_branch[1] for rotamer in rotamers: atom_list_2.append(set([rotamer.index1, rotamer.index2])) EXPECTED_INDICES_1 = [ set([9, 10]), set([8, 9]), set([7, 8]), set([6, 7]), set([5, 6]), set([2, 5]), set([0, 2]), set([0, 1]) ] EXPECTED_INDICES_2 = [ set([12, 11]), set([12, 13]), set([13, 14]), set([14, 15]), set([15, 16]), set([16, 17]), set([17, 18]) ] where_1 = list() for atom_pair in atom_list_1: if atom_pair in EXPECTED_INDICES_1: where_1.append(1) elif atom_pair in EXPECTED_INDICES_2: where_1.append(2) else: where_1.append(0) where_2 = list() for atom_pair in atom_list_2: if atom_pair in EXPECTED_INDICES_1: where_2.append(1) elif atom_pair in EXPECTED_INDICES_2: where_2.append(2) else: where_2.append(0) assert (all(i == 1 for i in where_1) and all(i == 2 for i in where_2)) or \ (all(i == 2 for i in where_1) and all(i == 1 for i in where_2)), "Invalid rotamer library " + \ "{}, {}".format(where_1, where_2) assert (all(i == 1 for i in where_1) and all(i == 2 for i in where_2) and len(where_1) == len(EXPECTED_INDICES_1) and len(where_2) == len(EXPECTED_INDICES_2)) or \ (all(i == 2 for i in where_1) and all(i == 1 for i in where_2) and len(where_1) == len(EXPECTED_INDICES_2) and len(where_2) == len(EXPECTED_INDICES_1)), "Unexpected " + \ "number of rotamers"
def test_PDB_connectivity_template(self): """ It tests the initialization of an offpele's Molecule representation from a PDB file without connectivity and a connectivity template. """ # Initialize an empty Molecule object molecule = Molecule() assert molecule.connectivity_template is None, \ 'Unexpected connectivity template' # Initialize a Molecule from a PDB without connectivity and # without a connectivity template ligand_path = get_data_file_path( 'ligands/BNZ_without_connectivity.pdb') molecule = Molecule(ligand_path) expected_bond_ids = [(1, 0, False), (2, 1, False), (3, 2, False), (4, 3, False), (5, 4, False), (5, 0, False), (6, 0, False), (7, 1, False), (8, 2, False), (9, 3, False), (10, 4, False), (11, 5, False)] for bond in molecule.rdkit_molecule.GetBonds(): bond_id = (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), bond.GetIsAromatic()) assert bond_id in expected_bond_ids, 'Unexpected bond id ' \ + '{}'.format(bond_id) # Initialize a Molecule from a PDB without connectivity but with # a connectivity template template_path = get_data_file_path('ligands/BNZ.pdb') template = Molecule(template_path) ligand_path = get_data_file_path( 'ligands/BNZ_without_connectivity.pdb') molecule = Molecule(ligand_path, connectivity_template=template.rdkit_molecule) expected_bond_ids = [(1, 0, True), (2, 1, True), (3, 2, True), (4, 3, True), (5, 4, True), (5, 0, True), (6, 0, False), (7, 1, False), (8, 2, False), (9, 3, False), (10, 4, False), (11, 5, False)] for bond in molecule.rdkit_molecule.GetBonds(): bond_id = (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), bond.GetIsAromatic()) assert bond_id in expected_bond_ids, 'Unexpected bond id ' \ + '{}'.format(bond_id) # Initialize a Molecule from a PDB with connectivity and with # a connectivity template template_path = get_data_file_path('ligands/BNZ.pdb') template = Molecule(template_path) ligand_path = get_data_file_path('ligands/BNZ.pdb') molecule = Molecule(ligand_path, connectivity_template=template.rdkit_molecule) expected_bond_ids = [(0, 1, True), (1, 2, True), (2, 3, True), (3, 4, True), (4, 5, True), (0, 5, True), (0, 6, False), (1, 7, False), (2, 8, False), (3, 9, False), (4, 10, False), (5, 11, False)] for bond in molecule.rdkit_molecule.GetBonds(): bond_id = (bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), bond.GetIsAromatic()) assert bond_id in expected_bond_ids, 'Unexpected bond id ' \ + '{}'.format(bond_id)