Exemple #1
0
def test_from_smiles(smiles):
    """
    Make sure hydrogens are added to a molecule when needed.
    """
    mol = Ligand.from_smiles(smiles_string=smiles, name="methane")
    # count the number of hydrogens
    hs = sum([1 for atom in mol.atoms if atom.atomic_symbol == "H"])
    assert hs == 4
Exemple #2
0
def test_torsion_finder_multiple():
    """
    Find non hydrogen torsions for multiple rotatable bonds.
    """
    mol = Ligand.from_smiles("CCO", "ethanol")
    bonds = mol.find_rotatable_bonds()
    for bond in bonds:
        torsion = find_heavy_torsion(molecule=mol, bond=bond)
        check_proper_torsion(torsion=torsion, molecule=mol)
Exemple #3
0
def test_to_rdkit_complicated_stereo():
    """
    Make sure we can convert a complicated molecule with multiple stereo centres to rdkit.
    """
    mol = Ligand.from_smiles(
        "[H][C@]1([C@@]([C@](O[C@@]1([H])C([H])([H])OP(=O)(O[H])O[H])([H])N2C(=C([N+](C2([H])[H])([H])[H])C(=O)N([H])[H])O[H])([H])O[H])O[H]",
        name="complicated",
    )
    mol.to_rdkit()
Exemple #4
0
def test_torsion_special_case_double():
    """
    Make sure special cases changes the scan range for a bond.
    """
    mol = Ligand.from_smiles("CO", "methanol")
    t_scan = TorsionScan1D()
    t_scan.clear_avoided_torsions()
    # add the special case with non-default range
    t_scan.add_special_torsion(smirks="[*:1]-[OH1:2]", scan_range=(0, 180))
    # get the one rotatable bond
    bond = mol.find_rotatable_bonds()[0]
    scan_range = t_scan._get_scan_range(molecule=mol, bond=bond)
    assert scan_range == (0, 180)
Exemple #5
0
def test_to_rdkit_kekule(molecule):
    """
    Make sure we can correctly convert a molecule to rdkit when it has mixed aromatic and non-aromatic rings.
    This test is due to an kekule error where non aromatic atoms were sometimes given aromatic bonds.
    """
    mol = Ligand.from_smiles(molecule, name="test")
    rd_mol = mol.to_rdkit()
    for atom in rd_mol.GetAtoms():
        qb_atom = mol.atoms[atom.GetIdx()]
        assert atom.GetIsAromatic() is qb_atom.aromatic
    for bond in rd_mol.GetBonds():
        qb_bond = mol.bonds[bond.GetIdx()]
        assert qb_bond.aromatic is bond.GetIsAromatic()
        assert qb_bond.bond_order == bond.GetBondTypeAsDouble()
Exemple #6
0
def run(
    input_file: Optional[str] = None,
    smiles: Optional[str] = None,
    name: Optional[str] = None,
    multiplicity: int = 1,
    end: Optional[str] = None,
    skip_stages: Optional[List[str]] = None,
    config: Optional[str] = None,
    protocol: Optional[str] = None,
    cores: Optional[int] = None,
    memory: Optional[int] = None,
):
    """Run the QUBEKit parametrisation workflow on an input molecule."""
    # make sure we have an input or smiles not both
    if input_file is not None and smiles is not None:
        raise RuntimeError(
            "Please supply either the name of the input file or a smiles string not both."
        )
    # load the molecule
    if input_file is not None:
        molecule = Ligand.from_file(file_name=input_file,
                                    multiplicity=multiplicity)
    else:
        if name is None:
            raise RuntimeError(
                "Please also pass a name for the molecule when starting from smiles."
            )
        molecule = Ligand.from_smiles(smiles_string=smiles,
                                      name=name,
                                      multiplicity=multiplicity)

    # load workflow
    workflow = prep_config(config_file=config,
                           memory=memory,
                           cores=cores,
                           protocol=protocol)

    # move into the working folder and run
    with folder_setup(
            f"QUBEKit_{molecule.name}_{datetime.now().strftime('%Y_%m_%d')}"):
        # write the starting molecule
        molecule.to_file(file_name=f"{molecule.name}.pdb")
        workflow.new_workflow(molecule=molecule,
                              skip_stages=skip_stages,
                              end=end)
Exemple #7
0
def test_double_dihedral(tmpdir):
    """Test running a molecule with two rotatable bonds."""
    with tmpdir.as_cwd():
        mol = Ligand.from_smiles("CCO", "ethanol")
        # build a scanner with grid spacing 60 and clear out avoided methyl
        tdrive = TorsionDriver(
            program="rdkit",
            method="uff",
            basis=None,
            cores=1,
            memory=1,
            n_workers=1,
            grid_spacing=60,
        )
        t_scan = TorsionScan1D(torsion_driver=tdrive)
        t_scan.clear_avoided_torsions()
        result_mol = t_scan.run(molecule=mol)
        assert len(result_mol.qm_scans) == 2
        # make sure input molecule coords were not changed
        assert np.allclose(mol.coordinates, result_mol.coordinates)
Exemple #8
0
def mol_47():
    return Ligand.from_smiles("CC(C)(O)CCC(C)(C)O", "mol_47")
Exemple #9
0
def run(
    bulk_file: str,
    skip_stages: Optional[List[str]] = None,
    end: Optional[str] = None,
    restart: Optional[str] = None,
    config: Optional[str] = None,
    protocol: Optional[str] = None,
    cores: Optional[int] = None,
    memory: Optional[int] = None,
) -> None:
    """Run the QUBEKit parametrisation workflow on a collection of molecules in serial.

    Loop over the molecules in order of the CSV file.
    """
    import glob
    import os

    from qubekit.utils.helpers import mol_data_from_csv

    home = os.getcwd()
    # load all inputs
    bulk_data = mol_data_from_csv(bulk_file)

    # start main molecule loop
    for name, mol_data in bulk_data.items():
        print(f"Analysing: {name}")
        try:
            if restart is not None or mol_data["restart"] is not None:
                # we are trying to restart a run, find the folder
                # should only be one
                fname = name.split(".")[0]
                folder = glob.glob(f"QUBEKit_{fname}_*")[0]
                with folder_setup(folder):
                    results = WorkFlowResult.parse_file("workflow_result.json")
                    if config is None:
                        # if we have no new config load from results
                        workflow = prep_config(
                            results=results, cores=cores, memory=memory, protocol=None
                        )
                    else:
                        # load the new config file
                        workflow = prep_config(
                            config_file=config, cores=cores, memory=memory
                        )

                    workflow.restart_workflow(
                        start=restart or mol_data["restart"],
                        skip_stages=skip_stages,
                        end=end or mol_data["end"],
                        result=results,
                    )

            else:
                if mol_data["smiles"] is not None:
                    molecule = Ligand.from_smiles(
                        smiles_string=mol_data["smiles"], name=name
                    )
                else:
                    molecule = Ligand.from_file(file_name=name)

                # load the CLI config or the csv config, else default
                workflow = prep_config(
                    config_file=config or mol_data["config_file"],
                    memory=memory,
                    cores=cores,
                    protocol=protocol,
                )
                # move into the working folder and run
                with folder_setup(
                    f"QUBEKit_{molecule.name}_{datetime.now().strftime('%Y_%m_%d')}"
                ):
                    # write the starting molecule
                    molecule.to_file(file_name=f"{molecule.name}.pdb")
                    workflow.new_workflow(
                        molecule=molecule,
                        skip_stages=skip_stages,
                        end=end or mol_data["end"],
                    )
        except WorkFlowExecutionError:
            os.chdir(home)
            print(
                f"An error was encountered while running {name} see folder for more info."
            )
            continue