def setUpClass(cls): cls.files_folder = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'files') os.mkdir('temp') os.chdir('temp') copy(os.path.join(cls.files_folder, 'acetone.pdb'), 'acetone.pdb') cls.molecule_pdb = Ligand('acetone.pdb') copy(os.path.join(cls.files_folder, 'acetone.mol2'), 'acetone.mol2') cls.molecule_mol2 = Ligand('acetone.mol2') os.chdir('../')
def handle_bulk(self): """ Getting and setting configs for bulk runs is a little different, requiring this method. The configs are taken from the .csv, then the .ini, then the terminal. This is repeated for each molecule in the bulk run, then Execute is called. Configs cannot be changed between molecule analyses as config data is only loaded once at the start; -restart is required for that. """ csv_file = self.args.bulk_run # mol_data_from_csv handles defaults if no argument is given bulk_data = mol_data_from_csv(csv_file) names = list(bulk_data) home = os.getcwd() for name in names: printf(f'Analysing: {name}\n') # Get pdb from smiles or name if no smiles is given if bulk_data[name]['smiles'] is not None: smiles_string = bulk_data[name]['smiles'] self.molecule = Ligand(smiles_string, name) else: # TODO Different file types (should be easy as long as they're rdkit-readable) # Initialise molecule, ready to add configs to it self.molecule = Ligand(f'{name}.pdb') # Read each row in bulk data and set it to the molecule object for key, val in bulk_data[name].items(): setattr(self.molecule, key, val) self.molecule.skip = None # Using the config file from the .csv, gather the .ini file configs file_configs = Configure().load_config(self.molecule.config_file) for key, val in file_configs.items(): setattr(self.molecule, key, val) # Handle configs which are changed by terminal commands for key, val in vars(self.args).items(): if val is not None: setattr(self.molecule, key, val) # Now that all configs are stored correctly: execute. Execute(self.molecule) os.chdir(home) sys.exit('Bulk analysis complete.\nUse QUBEKit -progress to view the completion progress of your molecules')
def setUpClass(cls): """ Write the big string in test_structures to a file to be used for testing. Cannot use actual files as pathing causes issues. """ with open('acetone.pdb', 'w+') as pdb_test_file: pdb_test_file.write(acetone) with open('acetone.mol2', 'w+') as mol2_test_file: mol2_test_file.write(acetone_mol2) cls.molecule_pdb = Ligand('acetone.pdb') cls.molecule_mol2 = Ligand('acetone.mol2')
def test_smiles(self): """Ensure molecule is correctly generated from a smiles string.""" molecule_smiles = Ligand('CCC', 'propane') angles = { (1, 0, 3): 113.51815048217622, (1, 0, 4): 108.585923222101, (1, 0, 5): 106.72547221240829, (3, 0, 4): 108.67471750338844, (3, 0, 5): 109.86966536530876, (4, 0, 5): 109.3960638804494, (0, 1, 2): 112.47821537702777, (0, 1, 6): 106.25702918976113, (0, 1, 7): 113.72590402122567, (2, 1, 6): 106.3390387838715, (2, 1, 7): 111.69729882714941, (6, 1, 7): 105.65819247884409, (1, 2, 8): 108.59874810898711, (1, 2, 9): 112.19545440609062, (1, 2, 10): 111.67294842834627, (8, 2, 9): 111.33448705926884, (8, 2, 10): 107.47750840394838, (9, 2, 10): 105.46240504563437 } # loop over the angles and make sure they are almost equal to 7 d.p # the dictionaries will always be made in the same order unless the RDKit ordering changes. for angle, value in angles.items(): self.assertAlmostEqual(molecule_smiles.angle_values[angle], value)
def __call__(self, pars, namespace, values, option_string=None): """This function is executed when Torsion maker is called.""" # TODO Should this be here? # load in the ligand molecule mol = Ligand(values) # Prompt the user for the scan order scanner = TorsionScan(mol) scanner.find_scan_order() # Write out the scan file with open('QUBE_torsions.txt', 'w+') as qube: qube.write( '# dihedral definition by atom indices starting from 1\n# i j k l\n' ) for scan in mol.scan_order: scan_di = mol.dihedrals[scan][0] qube.write( f' {scan_di[0]:2} {scan_di[1]:2} {scan_di[2]:2} {scan_di[3]:2}\n' ) printf('QUBE_torsions.txt made.') sys.exit()
def setUp(self): """ Set up the ligand testing class, make temp folder and copy the pdb and mol2 over """ self.home = os.getcwd() self.test_folder = os.path.join(os.path.dirname(__file__), 'files') # Make the temp folder and move there with the required files with tempfile.TemporaryDirectory() as temp: os.chdir(temp) copy(os.path.join(self.test_folder, 'acetone.pdb'), 'acetone.pdb') self.molecule_pdb = Ligand('acetone.pdb') copy(os.path.join(self.test_folder, 'acetone.mol2'), 'acetone.mol2') self.molecule_mol2 = Ligand('acetone.mol2')
def test_smiles(self): # create a new molecule from a smiles string molecule_smiles = Ligand('CCC', 'ethane') # check the internal structures angles = { (1, 0, 3): 113.51815048217622, (1, 0, 4): 108.585923222101, (1, 0, 5): 106.72547221240829, (3, 0, 4): 108.67471750338844, (3, 0, 5): 109.86966536530876, (4, 0, 5): 109.3960638804494, (0, 1, 2): 112.47821537702777, (0, 1, 6): 106.25702918976113, (0, 1, 7): 113.72590402122567, (2, 1, 6): 106.3390387838715, (2, 1, 7): 111.69729882714941, (6, 1, 7): 105.65819247884409, (1, 2, 8): 108.59874810898711, (1, 2, 9): 112.19545440609062, (1, 2, 10): 111.67294842834627, (8, 2, 9): 111.33448705926884, (8, 2, 10): 107.47750840394838, (9, 2, 10): 105.46240504563437 } self.assertEqual(angles, molecule_smiles.angle_values)
def setUpClass(cls): """ Create temp working directory and copy across test files. Initialise test molecule (acetone) with Ligand(). """ cls.files_folder = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'files') os.mkdir('temp') os.chdir('temp') copy(os.path.join(cls.files_folder, 'acetone.pdb'), 'acetone.pdb') cls.molecule_pdb = Ligand('acetone.pdb') cls.molecule_pdb.testing = True copy(os.path.join(cls.files_folder, 'acetone.mol2'), 'acetone.mol2') cls.molecule_mol2 = Ligand('acetone.mol2') cls.molecule_mol2.testing = True os.chdir('../')
def setUpClass(cls): cls.files_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files') # Make the temp folder and move there with the required files os.mkdir('temp') os.chdir('temp') copy(os.path.join(cls.files_folder, 'acetone.pdb'), 'acetone.pdb') cls.molecule = Ligand('acetone.pdb')
def setUpClass(cls): """ Write the big string above to a file to be used for testing. Cannot use actual files as pathing causes issues. """ with open('acetone.pdb', 'w+') as pdb_test_file: pdb_test_file.write(acetone) cls.molecule = Ligand('acetone.pdb')
def load_molecule(self): """Load the molecule into the gui and make an instance of the Ligand class.""" # Open up the file explorer filename = self.load_file(["pdb", "mol2", "mol", "sdf"]) if ".pdb" in filename or ".mol2" in filename or "mol" in filename: # Instance the QUBEKit class self.molecule = Ligand(filename) self.viewer.load_molecule(filename) self.ligand_name.setText(f"{self.molecule.name}")
def load_molecule(self): """Load the molecule into the gui and make an instance of the Ligand class.""" # Open up the file explorer filename = self.load_file(['pdb', 'mol2', 'mol', 'sdf']) if '.pdb' in filename or '.mol2' in filename or 'mol' in filename: # Instance the QUBEKit class self.molecule = Ligand(filename) self.viewer.load_molecule(filename) self.ligand_name.setText(f'{self.molecule.name}')
def setUpClass(cls): """Create temp working directory and copy across test files.""" cls.files_folder = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'files') os.mkdir('temp') os.chdir('temp') copy(os.path.join(cls.files_folder, 'acetone.pdb'), 'acetone.pdb') cls.molecule = Ligand('acetone.pdb') cls.molecule.testing = True
def __init__(self): # First make sure the config folder has been made missing for conda and pip home = str(Path.home()) config_folder = f'{home}/QUBEKit_configs/' if not os.path.exists(config_folder): os.makedirs(config_folder) print(f'Making config folder at: {home}') self.args = self.parse_commands() # If it's a bulk run, handle it separately # TODO Add .sdf as possible bulk_run, not just .csv if self.args.bulk_run: self.handle_bulk() if self.args.restart is not None: # Find the pickled checkpoint file and load it as the molecule try: self.molecule = unpickle()[self.args.restart] except FileNotFoundError: raise FileNotFoundError('No checkpoint file found!') else: if self.args.smiles: self.file = RDKit().smiles_to_pdb(*self.args.smiles) else: self.file = self.args.input # Initialise molecule self.molecule = Ligand(self.file) # Find which config file is being used self.molecule.config = self.args.config_file # Handle configs which are in a file file_configs = Configure.load_config(self.molecule.config) for name, val in file_configs.items(): setattr(self.molecule, name, val) # Although these may be None always, they need to be explicitly set anyway. setattr(self.molecule, 'restart', None) setattr(self.molecule, 'end', None) setattr(self.molecule, 'skip', None) # Handle configs which are changed by terminal commands for name, val in vars(self.args).items(): if val is not None: setattr(self.molecule, name, val) # If restarting put the molecule back into the checkpoint file with the new configs if self.args.restart is not None: self.molecule.pickle(state=self.args.restart) # Now that all configs are stored correctly: execute. Execute(self.molecule)
def handle_bulk(self): """ Getting and setting configs for bulk runs is a little different, requiring this method. The configs are taken from the .csv, then the .ini, then the terminal. This is repeated for each molecule in the bulk run, then Execute is called. Configs cannot be changed between molecule analyses as config data is only loaded once at the start. """ csv_file = self.args.bulk_run # mol_data_from_csv handles defaults if no argument is given bulk_data = mol_data_from_csv(csv_file) names = list(bulk_data) for name in names: printf(f'Analysing: {name}\n') # Get pdb from smiles or name if no smiles is given if bulk_data[name]['smiles'] is not None: smiles_string = bulk_data[name]['smiles'] self.file = RDKit.smiles_to_pdb(smiles_string, name) else: self.file = f'{name}.pdb' # Initialise molecule, ready to add configs to it self.molecule = Ligand(self.file) # Read each row in bulk data and set it to the molecule object for key, val in bulk_data[name].items(): setattr(self.molecule, key, val) setattr(self.molecule, 'skip', []) # Using the config file from the .csv, gather the .ini file configs file_configs = Configure.load_config(self.molecule.config) for key, val in file_configs.items(): setattr(self.molecule, key, val) # TODO Maybe remove? Do we actually want bulk analyses editable via terminal commands? # Handle configs which are changed by terminal commands for key, val in vars(self.args).items(): if val is not None: setattr(self.molecule, key, val) # Now that all configs are stored correctly: execute. Execute(self.molecule) sys.exit( 'Bulk analysis complete.\nUse QUBEKit -progress to view the completion progress of your molecules' )
def __call__(self, pars, namespace, values, option_string=None): # load in the ligand mol = Ligand(values) # Prompt the user for the scan order scanner = TorsionScan(mol) scanner.find_scan_order() # Write out the scan file with open(f'{mol.name}.dihedrals', 'w+') as qube: qube.write('# dihedral definition by atom indices starting from 0\n# i j k l\n') for scan in mol.scan_order: scan_di = mol.dihedrals[scan][0] qube.write(f' {scan_di[0]:2} {scan_di[1]:2} {scan_di[2]:2} {scan_di[3]:2}\n') printf(f'{mol.name}.dihedrals made.') sys.exit()
def __init__(self): self.args = self.parse_commands() # If it's a bulk run, handle it separately # TODO Add .sdf as possible bulk_run, not just .csv if self.args.bulk_run: self.handle_bulk() if self.args.restart: self.file = [ file for file in os.listdir(os.getcwd()) if '.pdb' in file ][0] else: if self.args.smiles: self.file = RDKit.smiles_to_pdb(self.args.smiles) else: self.file = self.args.input # Initialise molecule self.molecule = Ligand(self.file) # Find which config file is being used self.molecule.config = self.args.config_file # Handle configs which are in a file file_configs = Configure.load_config(self.molecule.config) for name, val in file_configs.items(): setattr(self.molecule, name, val) # Although these may be None always, they need be explicitly set anyway. setattr(self.molecule, 'restart', None) setattr(self.molecule, 'end', None) setattr(self.molecule, 'skip', None) # Handle configs which are changed by terminal commands for name, val in vars(self.args).items(): if val is not None: setattr(self.molecule, name, val) # Now that all configs are stored correctly: execute. Execute(self.molecule)
def load_molecule(): molecule = Ligand('CO', 'methanol') ExtractChargeData(molecule).extract_charge_data()
def test_pdb_reader(test_input, expected): mol = Ligand('acetone.pdb') mol.testing = True assert getattr(mol, test_input) == expected
def test_smiles_reader(test_input, expected): mol = Ligand("CC(=O)C", "acetone") mol.testing = True assert getattr(mol, test_input) == expected
def test_mol2_reader(test_input, expected): mol = Ligand("acetone.mol2") mol.testing = True assert getattr(mol, test_input) == expected
ds = client.get_collection("TorsionDriveDataset", "OpenFF Fragmenter Phenyl Benchmark") # Access the B3LYP-D3 data ds.query("B3LYP-D3") print('Getting TorsionDrive record') # Extract the tdrive record to find the initial input molecule td = ds.df.loc["c1c[cH:1][c:2](cc1)[C:3](=[O:4])O", "B3LYP-D3"] # Get the molecule id that can be used to make a qubekit molecule mol_id = td.initial_molecule molecule = client.query_molecules(id=mol_id)[0] print('Creating QUBEKit ligand molecule') # Instance QUBEKit ligand from a json dict mol = Ligand(molecule.json_dict(), 'torsion_example') # Now we should reset the basis and theory to match mol.basis = 'dzvp' mol.theory = 'b3lyp-d3bj' print('Parameterising using Anetchamber') # Now check the structure of the molecule and assign initial parameters using antechamber mol.write_pdb() AnteChamber(mol) # Get the central bond of the scanned dihedral dihedral = td.keywords.dihedrals[0] scan = (dihedral[1], dihedral[2]) # The ligand needs to know which torsion of the two rotatable options it has found is being fit mol.scan_order = [scan] # This is the central bond identified by td.keywords.dihedrals
def __init__(self): # First make sure the config folder has been made missing for conda and pip home = os.path.expanduser('~') config_folder = os.path.join(home, 'QUBEKit_configs') if not os.path.exists(config_folder): os.makedirs(config_folder) printf(f'Making config folder at: {home}') self.args = self.parse_commands() # If we are doing the torsion test add the attribute to the molecule so we can catch it in execute if self.args.torsion_test: self.args.restart = 'finalise' # If it's a bulk run, handle it separately # TODO Add .sdf as possible bulk_run, not just .csv if self.args.bulk_run is not None: self.handle_bulk() elif self.args.restart is not None: # Find the pickled checkpoint file and load it as the molecule try: self.molecule = unpickle()[self.args.restart] except KeyError: raise KeyError('This stage was not found in the log file; was the previous stage completed?') else: # Initialise molecule if self.args.smiles: self.molecule = Ligand(*self.args.smiles) # Now we should create the initial molecule and else: self.molecule = Ligand(self.args.input) # Find which config file is being used self.molecule.config_file = self.args.config_file # Handle configs which are in a file file_configs = Configure().load_config(self.molecule.config_file) for name, val in file_configs.items(): setattr(self.molecule, name, val) # Although these may be None always, they need to be explicitly set anyway. self.molecule.restart = None self.molecule.end = None self.molecule.skip = None # Handle configs which are changed by terminal commands for name, val in vars(self.args).items(): if val is not None: setattr(self.molecule, name, val) # Now we need to remove torsion_test as it is passed from the command line if self.args.torsion_test is False: delattr(self.molecule, 'torsion_test') # Now check if we have been supplied a dihedral file and a constraints file if self.args.dihedral_file: self.molecule.read_scan_order(self.args.dihedral_file) if self.args.constraints_file: self.molecule.constraints_file = self.args.constaints_file # If restarting put the molecule back into the checkpoint file with the new configs if self.args.restart is not None: self.molecule.pickle(state=self.args.restart) # Now that all configs are stored correctly: execute. Execute(self.molecule)
def __init__(self, molecule_file=None, parent=None): super(LigandTab, self).__init__(parent) # Try to load the molecule if we have been passed a name if molecule_file is not None: self.molecule = Ligand(molecule_file) else: self.molecule = None # Set the main layout self.layout = QtWidgets.QVBoxLayout() # Add the main label self.main_label = QtWidgets.QLabel("QUBEKit Ligand setup") self.main_label.setFont(QtGui.QFont("Aerial", 16, QtGui.QFont.Bold)) if self.molecule is None: self.ligand_name = QtWidgets.QLabel( "Load molecule .pdb .mol2 file") else: self.ligand_name = QtWidgets.QLabel(f"{self.molecule.name}") # Add the file loader button self.file_button = QtWidgets.QPushButton("Load Molecule") self.file_button.clicked.connect(self.load_molecule) # Put the label and Button in there own box top_row = QtWidgets.QHBoxLayout() top_row.addWidget(self.ligand_name) top_row.addWidget(self.file_button) if molecule_file is not None: self.viewer = Viewer(self.molecule.filename) else: self.viewer = Viewer() # Add representation settings for the ligand self.representation_label = QtWidgets.QLabel("Representation") self.representation = QtWidgets.QComboBox() self.representation.addItems([ "Licorice", "hyperball", "spheres", "partialCharge", "ball+stick", "spacefill", ]) # Add text change logic self.representation.currentTextChanged.connect(self.change_rep) # Add own box for layout repersentation = QtWidgets.QHBoxLayout() repersentation.addWidget(self.representation_label) repersentation.addWidget(self.representation) # Add a surface control box self.surface_group = QtWidgets.QGroupBox("Surface Controls") self.surface_group.setCheckable(True) self.surface_label = QtWidgets.QLabel("Surface file") self.surface_file = QtWidgets.QPushButton("Load surface file") self.surface_file.clicked.connect(self.load_surface) # self.find # Set the master layout self.layout.addWidget(self.main_label) self.layout.addLayout(top_row) self.layout.addWidget(self.viewer.view) self.layout.addLayout(repersentation) self.setLayout(self.layout)
# Extract hessian try: hessian = client.query_results(molecule=optimisation.final_molecule, driver="hessian")[0].return_result except IndexError: # Molecule has been optimised but no hessian has been calculated yet continue # Reshape hessian conversion = constants.HA_TO_KCAL_P_MOL / (constants.BOHR_TO_ANGS ** 2) hessian = np.array(hessian).reshape(int(len(hessian) ** 0.5), -1) * conversion # Extract optimised structure opt_struct = client.query_procedures(id=opt_record)[0].get_final_molecule() # Initialise Ligand object using the json dict from qcengine mol = Ligand(opt_struct.json_dict(), name='initial_test') # Set the qm coords to the input coords from qcengine mol.coords['qm'] = mol.coords['input'] # Insert hessian and optimised coordinates mol.hessian = hessian mol.parameter_engine = 'none' # Create empty parameter dicts Parametrisation(mol).gather_parameters() print(item) with open('Modified_Seminario_Bonds.txt', 'a+') as bonds_file, \ open('Modified_Seminario_Angles.txt', 'a+') as angles_file: