def test_explicit_hydrogens(self): """ It checks initialization of a Molecule with the explicit hydrogens flag. """ # Load ethane from SMILES with implicit hydrogen atoms molecule = Molecule(smiles='CC') atom_names = molecule.get_pdb_atom_names() for atom_name in atom_names: assert 'H' not in atom_name, 'Unexpected H in molecule without ' \ + 'explicit hydrogen atoms and hydrogens_are_explicit ' \ + 'set to True' # Load ethane from SMILES without explicit hydrogen atoms molecule = Molecule(smiles='CC', hydrogens_are_explicit=False) atom_names = molecule.get_pdb_atom_names() found_hydrogen = False for atom_name in atom_names: if 'H' in atom_name: found_hydrogen = True break assert found_hydrogen, 'Hydrogen not found regardless of setting ' \ + 'hydrogens_are_explicit to False' # Load ethane from SMILES with explicit hydrogen atoms molecule = Molecule(smiles='[H]C([H])([H])C([H])([H])([H])', hydrogens_are_explicit=True) atom_names = molecule.get_pdb_atom_names() found_hydrogen = False for atom_name in atom_names: if 'H' in atom_name: found_hydrogen = True break assert found_hydrogen, 'Hydrogen not found regardless of being ' \ + 'explicitly defined in the SMILES tag' # Load ethane from PDB with implicit hydrogen atoms pdb_path = get_data_file_path('tests/ethane_noH.pdb') molecule = Molecule(pdb_path, hydrogens_are_explicit=True) atom_names = molecule.get_pdb_atom_names() for atom_name in atom_names: assert 'H' not in atom_name, 'Unexpected H in molecule without ' \ + 'explicit hydrogen atoms and hydrogens_are_explicit ' \ + 'set to True' # Load ethane from PDB without explicit hydrogen atoms pdb_path = get_data_file_path('tests/ethane_noH.pdb') molecule = Molecule(pdb_path, hydrogens_are_explicit=False) atom_names = molecule.get_pdb_atom_names() found_hydrogen = False for atom_name in atom_names: if 'H' in atom_name: found_hydrogen = True break assert found_hydrogen, 'Hydrogen not found regardless of setting ' \ + 'hydrogens_are_explicit to False'
def test_datalocal_paths_for_offopls(self): """ It tests the datalocal paths assignment for OpenFF-OPLS2005 force field. """ from peleffy.utils import OutputPathHandler from peleffy.forcefield import OpenFFOPLS2005ForceField # Load benzene molecule molecule = Molecule(smiles='c1ccccc1', name='benzene', tag='BNZ', hydrogens_are_explicit=False) molecule._forcefield = OpenFFOPLS2005ForceField('OPLS2005') # Load force field hybridff = OpenFFOPLS2005ForceField( 'openff_unconstrained-1.2.1.offxml') # Molecule's tag tag = molecule.tag # Initialize output handler without output_path output_handler = OutputPathHandler(molecule, hybridff, as_datalocal=True) # Validate output paths assert output_handler.get_rotamer_library_path( create_missing_folders=False) == \ './DataLocal/LigandRotamerLibs/' \ + '{}.rot.assign'.format(tag.upper()), \ 'Unexpected default rotamer library path' assert output_handler.get_impact_template_path( create_missing_folders=False) == \ './DataLocal/Templates/OpenFF/Parsley/' \ + '{}z'.format(tag.lower()), \ 'Unexpected default Impact template path' assert output_handler.get_solvent_template_path( create_missing_folders=False) == \ './DataLocal/OBC/ligandParams.txt', \ 'Unexpected default solvent parameters path' assert output_handler.get_conformation_library_path( create_missing_folders=False) == \ './DataLocal/Conformations/' \ + '{}.conformation'.format(tag.upper()), \ 'Unexpected default conformation library path' # Initialize output handler with an output_path set with tempfile.TemporaryDirectory() as tmpdir: output_handler = OutputPathHandler( molecule, hybridff, as_datalocal=True, output_path=os.path.join(tmpdir, 'output')) assert output_handler.get_rotamer_library_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/LigandRotamerLibs/' + '{}.rot.assign'.format(tag.upper())), \ 'Unexpected default rotamer library path' assert output_handler.get_impact_template_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/Templates/' + 'OpenFF/Parsley/{}z'.format(tag.lower())), \ 'Unexpected default Impact template path' assert output_handler.get_solvent_template_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/OBC/ligandParams.txt'), \ 'Unexpected default solvent parameters path' assert output_handler.get_conformation_library_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output/DataLocal/Conformations/' \ + '{}.conformation'.format(tag.upper())), \ 'Unexpected default conformation library path' # Initialize output handler without output_path output_handler = OutputPathHandler(molecule, hybridff, as_datalocal=True) # Set force field source for nonbonding parameters hybridff.set_nonbonding_parameters('opls2005') # Validate output paths assert output_handler.get_rotamer_library_path( create_missing_folders=False) == \ './DataLocal/LigandRotamerLibs/' \ + '{}.rot.assign'.format(tag.upper()), \ 'Unexpected default rotamer library path' assert output_handler.get_impact_template_path( create_missing_folders=False) == \ './DataLocal/Templates/OPLS2005/HeteroAtoms/' \ + '{}z'.format(tag.lower()), \ 'Unexpected default Impact template path' assert output_handler.get_solvent_template_path( create_missing_folders=False) == \ './DataLocal/OBC/ligandParams.txt', \ 'Unexpected default solvent parameters path' assert output_handler.get_conformation_library_path( create_missing_folders=False) == \ './DataLocal/Conformations/' \ + '{}.conformation'.format(tag.upper()), \ 'Unexpected default conformation library path' # Initialize output handler with an output_path set with tempfile.TemporaryDirectory() as tmpdir: output_handler = OutputPathHandler( molecule, hybridff, as_datalocal=True, output_path=os.path.join(tmpdir, 'output')) assert output_handler.get_rotamer_library_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/LigandRotamerLibs/' + '{}.rot.assign'.format(tag.upper())), \ 'Unexpected default rotamer library path' assert output_handler.get_impact_template_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/Templates/OPLS2005/' + 'HeteroAtoms/{}z'.format(tag.lower())), \ 'Unexpected default Impact template path' assert output_handler.get_solvent_template_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/OBC/ligandParams.txt'), \ 'Unexpected default solvent parameters path' assert output_handler.get_conformation_library_path( create_missing_folders=False) == \ os.path.join(tmpdir, 'output', 'DataLocal/Conformations/', '{}.conformation'.format(tag.upper())), \ 'Unexpected default conformation library path'
def test_PDB_connectivity_template(self): """ It tests the initialization of an peleffy'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/benzene_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/benzene.pdb') template = Molecule(template_path) ligand_path = get_data_file_path( 'ligands/benzene_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/benzene.pdb') template = Molecule(template_path) ligand_path = get_data_file_path( 'ligands/benzene.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)
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/benzene.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', hydrogens_are_explicit=False) 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', hydrogens_are_explicit=False) 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', hydrogens_are_explicit=False) 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_terminal_rotamer_filtering(self): """ It tests the rotamer library builder when the terminal rotatable bonds are ignored. """ LIGAND_PATH = 'ligands/oleic_acid.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_rotamer_core_constraint(self): """ It tests the rotamer library builder when constraining its core to contain a specific atom. """ LIGAND_PATH = 'ligands/oleic_acid.pdb' ligand_path = get_data_file_path(LIGAND_PATH) # Test atom index constraint molecule = Molecule(ligand_path, core_constraints=[ 19, ], exclude_terminal_rotamers=False) rotamers_per_branch = molecule.rotamers assert len(rotamers_per_branch) == 1, "Found an invalid number " + \ "of branches: {}".format(len(rotamers_per_branch)) atom_list = list() for rotamer in rotamers_per_branch[0]: atom_list.append(set([rotamer.index1, rotamer.index2])) EXPECTED_INDICES = [ set([18, 19]), set([17, 18]), set([16, 17]), set([15, 16]), set([14, 15]), set([13, 14]), set([12, 13]), set([11, 12]), set([9, 10]), set([8, 9]), set([7, 8]), set([6, 7]), set([5, 6]), set([2, 5]), set([0, 2]), set([0, 1]) ] assert len(atom_list) == len(EXPECTED_INDICES), "Unexpected " + \ "number of rotamers" assert all(atom_pair in EXPECTED_INDICES for atom_pair in atom_list), \ "Invalid rotamer library" # Test PDB atom name constraint molecule = Molecule(ligand_path, core_constraints=[ ' C18', ], exclude_terminal_rotamers=False) rotamers_per_branch = molecule.rotamers assert len(rotamers_per_branch) == 1, "Found an invalid number " + \ "of branches: {}".format(len(rotamers_per_branch)) atom_list = list() for rotamer in rotamers_per_branch[0]: atom_list.append(set([rotamer.index1, rotamer.index2])) EXPECTED_INDICES = [ set([18, 19]), set([17, 18]), set([16, 17]), set([15, 16]), set([14, 15]), set([13, 14]), set([12, 13]), set([11, 12]), set([9, 10]), set([8, 9]), set([7, 8]), set([6, 7]), set([5, 6]), set([2, 5]), set([0, 2]), set([0, 1]) ] assert len(atom_list) == len(EXPECTED_INDICES), "Unexpected " + \ "number of rotamers" assert all(atom_pair in EXPECTED_INDICES for atom_pair in atom_list), \ "Invalid rotamer library" # Test core constraint with terminal exclusion molecule = Molecule(ligand_path, core_constraints=[ ' C18', ], exclude_terminal_rotamers=True) rotamers_per_branch = molecule.rotamers assert len(rotamers_per_branch) == 1, "Found an invalid number " + \ "of branches: {}".format(len(rotamers_per_branch)) atom_list = list() for rotamer in rotamers_per_branch[0]: atom_list.append(set([rotamer.index1, rotamer.index2])) EXPECTED_INDICES = [ set([17, 18]), set([16, 17]), set([15, 16]), set([14, 15]), set([13, 14]), set([12, 13]), set([11, 12]), set([9, 10]), set([8, 9]), set([7, 8]), set([6, 7]), set([5, 6]), set([2, 5]), set([0, 2]), set([0, 1]) ] assert len(atom_list) == len(EXPECTED_INDICES), "Unexpected " + \ "number of rotamers" assert all(atom_pair in EXPECTED_INDICES for atom_pair in atom_list), \ "Invalid rotamer library" # Test core constraint with a central core molecule = Molecule(ligand_path, core_constraints=[ ' C9 ', ], 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" # Test core constraint with a multiple central core molecule = Molecule(ligand_path, core_constraints=[' C8 ', ' C9 ', ' C10'], 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([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 run_peleffy(pdb_file, forcefield_name=DEFAULT_OFF_FORCEFIELD, resolution=DEFAULT_RESOLUTION, charge_method=DEFAULT_CHARGE_METHOD, charges_from_file=None, chain=None, exclude_terminal_rotamers=True, output=None, with_solvent=False, as_datalocal=False, conformation_path=None): """ It runs peleffy. Parameters ---------- pdb_file : str The path to the pdb_file to parameterize with peleffy forcefield_name : str The name of an OpenForceField's forcefield resolution : float The resolution in degrees for the rotamer library. Default is 30 charge_method : str The name of the method to use to compute partial charges. Default is 'am1bcc' charges_from_file : str The file containing the partial charges to assign to the molecule. Default is None chain : str Chain to the molecule if the PDB contains multiple molecules. exclude_terminal_rotamers : bool Whether to exclude terminal rotamers or not output : str Path where output files will be saved with_solvent : bool Whether to generate and save the solvent parameters for the input molecule or not as_datalocal : bool Whether to save output files following PELE's DataLocal hierarchy or not conformation_path: str Path to the BCE server outupt to use to extract dihedral angles dihedral_mode: str Select what kind of dihedrals to extract (all or only flexible) """ if charges_from_file is not None: charge_method_str = 'file\n' \ + ' - Charge file: {}'.format(charges_from_file) charge_method = 'dummy' else: charge_method_str = charge_method log = Logger() log.info('-' * 60) log.info('Open Force Field parameterizer for PELE', peleffy.__version__) log.info('-' * 60) log.info(' - General:') log.info(' - Input PDB:', pdb_file) log.info(' - Output path:', output) log.info(' - Write solvent parameters:', with_solvent) log.info(' - DataLocal-like output:', as_datalocal) log.info(' - Parameterization:') log.info(' - Force field:', forcefield_name) log.info(' - Charge method:', charge_method_str) log.info(' - Rotamer library:') log.info(' - Resolution:', resolution) log.info(' - Exclude terminal rotamers:', exclude_terminal_rotamers) log.info('-' * 60) from peleffy.topology import Molecule, BCEConformations from peleffy.template import Impact from peleffy.solvent import OBC2 from peleffy.forcefield import ForceFieldSelector from peleffy.topology import Topology from peleffy.utils import parse_charges_from_mae from peleffy.utils.input import PDBFile if not output: output = os.getcwd() # Initialize molecule if chain is not None: PDBreader = PDBFile(pdb_file) molecule = PDBreader.get_molecules_from_chain( selected_chain=chain, rotamer_resolution=resolution, exclude_terminal_rotamers=exclude_terminal_rotamers) else: molecule = Molecule( pdb_file, rotamer_resolution=resolution, exclude_terminal_rotamers=exclude_terminal_rotamers) # Initialize force field ff_selector = ForceFieldSelector() forcefield = ff_selector.get_by_name(forcefield_name) output_handler = OutputPathHandler(molecule, forcefield, output_path=output, as_datalocal=as_datalocal) # if conformation_path is set, we don't want a rotamer library if conformation_path is None: rotamer_library = peleffy.topology.RotamerLibrary(molecule) rotamer_library.to_file(output_handler.get_rotamer_library_path()) # Parameterize molecule with the selected force field log.info(' - Parameterizing molecule') parameters = forcefield.parameterize(molecule, charge_method=charge_method) # Update charge parameters from the MAE file if charges_from_file is not None: parameters = parse_charges_from_mae(charges_from_file, parameters) # Generate the molecular topology topology = Topology(molecule, parameters) log.info(' - Parameters were built successfully:') log.info(' - {} atoms'.format(len(topology.atoms))) log.info(' - {} bonds'.format(len(topology.bonds))) log.info(' - {} torsions'.format(len(topology.angles))) log.info(' - {} propers'.format(len(topology.propers))) log.info(' - {} impropers'.format(len(topology.impropers))) # Generate the impact template impact = Impact(topology) impact.to_file(output_handler.get_impact_template_path()) # Generate the solvent template if with_solvent: solvent = OBC2(topology) solvent.to_file(output_handler.get_solvent_template_path()) if conformation_path is not None: conformations = BCEConformations(topology, conformation_path) conformations.calculate() conformations.save(output_handler.get_conformation_library_path()) log.info(' - All files were generated successfully:') if conformation_path is None: log.info(' - {}'.format(output_handler.get_rotamer_library_path())) log.info(' - {}'.format(output_handler.get_impact_template_path())) if conformation_path is not None: log.info(' - {}'.format( output_handler.get_conformation_library_path())) if with_solvent: log.info(' - {}'.format(output_handler.get_solvent_template_path())) log.info('-' * 60)
def test_parameterizer(self): """It checks the parameterized method.""" def check(hybridff, molecule, ffld_file, reference_file): """ It checks the parameters obtained by the force field. Parameters ---------- hybridff : an OpenFFOPLS2005ForceField object The hybrid force field to employ in the parameterization along with the ffld_file molecule : a peleffy.topology.Molecule The peleffy's Molecule object to parameterize with the ffld file ffld_file : str The path to the precomputed ffld file from where the parameters will be extracted reference_file : str The path to the file containing the reference parameters """ parameters = parameterize_openffopls2005(hybridff, molecule, ffld_file) writable_parameters = convert_all_quantities_to_string(parameters) with open(reference_file) as f: compare_dicts(writable_parameters, json.load(f)) from peleffy.topology import Molecule from peleffy.forcefield import OpenFFOPLS2005ForceField from peleffy.utils import (get_data_file_path, convert_all_quantities_to_string) from .utils import compare_dicts, parameterize_openffopls2005 import json # Load molecule 1 molecule = Molecule(get_data_file_path('ligands/methane.pdb')) hybridff = OpenFFOPLS2005ForceField(self.FORCE_FIELD_NAME) ffld_file = get_data_file_path('tests/MET_ffld_output.txt') # 1st check check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/MET_openff-1.2.1_opls2005_parameters1.json')) # 2nd check hybridff.set_nonbonding_parameters('OPLS2005') check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/MET_openff-1.2.1_opls2005_parameters2.json')) # 3rd check hybridff.set_nonbonding_parameters('OpenFF') hybridff.set_bond_parameters('OPLS2005') check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/MET_openff-1.2.1_opls2005_parameters3.json')) # 4th check hybridff.set_nonbonding_parameters('OpenFF') hybridff.set_bond_parameters('OpenFF') hybridff.set_angle_parameters('OPLS2005') check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/MET_openff-1.2.1_opls2005_parameters4.json')) # 5th check hybridff.set_nonbonding_parameters('OPLS2005') hybridff.set_bond_parameters('OPLS2005') hybridff.set_angle_parameters('OPLS2005') check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/MET_openff-1.2.1_opls2005_parameters5.json')) # Load molecule 2 molecule = Molecule(get_data_file_path('ligands/ethylene.pdb')) hybridff = OpenFFOPLS2005ForceField(self.FORCE_FIELD_NAME) ffld_file = get_data_file_path('tests/ETL_ffld_output.txt') # 1st check check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/ETL_openff-1.2.1_opls2005_parameters1.json')) # 2nd check hybridff.set_nonbonding_parameters('OpenFF') hybridff.set_dihedral_parameters('OPLS2005') check( hybridff, molecule, ffld_file, get_data_file_path( 'tests/ETL_openff-1.2.1_opls2005_parameters2.json'))
def test_atom_degrees(self): """It checks that the atom degree getter works well.""" from peleffy.topology import Molecule from peleffy.utils.toolkits import RDKitToolkitWrapper from peleffy.utils import get_data_file_path wrapper = RDKitToolkitWrapper() pdb_path = get_data_file_path('ligands/methane.pdb') m = Molecule(pdb_path) degree_by_name = dict(zip(wrapper.get_atom_names(m), wrapper.get_atom_degrees(m))) assert degree_by_name == {' C1 ': 4, ' H1 ': 1, ' H2 ': 1, ' H3 ': 1, ' H4 ': 1}, \ 'Unexpected pairing between atom names and degrees' pdb_path = get_data_file_path('ligands/ethylene.pdb') m = Molecule(pdb_path) degree_by_name = dict(zip(wrapper.get_atom_names(m), wrapper.get_atom_degrees(m))) assert degree_by_name == {' C1 ': 3, ' C2 ': 3, ' H1 ': 1, ' H2 ': 1, ' H3 ': 1, ' H4 ': 1}, \ 'Unexpected pairing between atom names and degrees' pdb_path = get_data_file_path('ligands/acetylene.pdb') m = Molecule(pdb_path) degree_by_name = dict(zip(wrapper.get_atom_names(m), wrapper.get_atom_degrees(m))) assert degree_by_name == {' C1 ': 2, ' C2 ': 2, ' H1 ': 1, ' H2 ': 1}, \ 'Unexpected pairing between atom names and degrees' pdb_path = get_data_file_path('ligands/propionic_acid.pdb') m = Molecule(pdb_path) degree_by_name = dict(zip(wrapper.get_atom_names(m), wrapper.get_atom_degrees(m))) assert degree_by_name == {' C1 ': 4, ' C2 ': 4, ' C3 ': 3, ' O1 ': 1, ' O2 ': 2, ' H1 ': 1, ' H2 ': 1, ' H3 ': 1, ' H4 ': 1, ' H5 ': 1, ' H6 ': 1}, \ 'Unexpected pairing between atom names and degrees' pdb_path = get_data_file_path('ligands/trimethylglycine.pdb') m = Molecule(pdb_path) degree_by_name = dict(zip(wrapper.get_atom_names(m), wrapper.get_atom_degrees(m))) assert degree_by_name == {' C1 ': 4, ' N1 ': 4, ' C2 ': 4, ' C3 ': 4, ' C4 ': 4, ' C5 ': 3, ' O1 ': 1, ' O2 ': 1, ' H1 ': 1, ' H2 ': 1, ' H3 ': 1, ' H4 ': 1, ' H5 ': 1, ' H6 ': 1, ' H7 ': 1, ' H8 ': 1, ' H9 ': 1, ' H10': 1, ' H11': 1}, \ 'Unexpected pairing between atom names and degrees' pdb_path = get_data_file_path('ligands/malonate.pdb') m = Molecule(pdb_path) degree_by_name = dict(zip(wrapper.get_atom_names(m), wrapper.get_atom_degrees(m))) assert degree_by_name == {' O1 ': 1, ' C1 ': 3, ' O2 ': 1, ' C2 ': 4, ' C3 ': 3, ' O3 ': 2, ' O4 ': 1, ' H1 ': 1, ' H2 ': 1, ' H3 ': 1}, \ 'Unexpected pairing between atom names and degrees'