def test_parameter_round_trip(method, tmpdir, xml, openff, antechamber):
    """
    Check we can parametrise a molecule then write out the same parameters.
    """

    if method == "openff":
        param_method = openff
    else:
        param_method = antechamber

    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.sdf"))
        param_mol = param_method.run(mol)
        with open("serialised.xml") as old:
            with open("orig.xml", "w") as new:
                new.write(old.read())
        # write out params
        mol.write_parameters(file_name="test.xml")

        # make a second mol
        mol2 = Ligand.from_file(get_data("acetone.sdf"))
        param_mol2 = xml.run(molecule=mol2, input_files=["test.xml"])

        for bond in mol.bonds:
            bond_tuple = (bond.atom1_index, bond.atom2_index)
            bond1 = param_mol.BondForce[bond_tuple]
            bond2 = param_mol2.BondForce[bond_tuple]
            assert bond1.k == pytest.approx(bond2.k)
            assert bond1.length == pytest.approx(bond2.length)

        for angle in mol.angles:
            angle1 = param_mol.AngleForce[angle]
            angle2 = param_mol2.AngleForce[angle]
            assert angle1.k == pytest.approx(angle2.k)
            assert angle2.angle == pytest.approx(angle2.angle)

        for atom in range(mol.n_atoms):
            atom1 = param_mol.NonbondedForce[(atom, )]
            atom2 = param_mol2.NonbondedForce[(atom, )]
            assert atom1.charge == pytest.approx(atom2.charge)
            assert atom1.sigma == pytest.approx(atom2.sigma)
            assert atom1.epsilon == pytest.approx(atom2.epsilon)

        # loop over the round trip mol as we lose some parameters which are 0
        for dihedral in param_mol2.TorsionForce.parameters:
            other_dih = param_mol.TorsionForce[dihedral.atoms]
            for key in dihedral.__fields__:
                # openmm will not load any torsions which have k=0, this causes differences between antechamber and
                # qubekit when the phase is not as expected, this does not change the energy however as k=0
                if (key not in ["atoms", "attributes", "parameter_eval"]
                        and "phase" not in key):
                    assert getattr(dihedral, key) == pytest.approx(
                        getattr(other_dih, key))
def test_parameter_tags(tmpdir, force_group, ff_group, key, terms):
    """
    Make sure that the parameter tagger tags correct terms.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(file_name=get_data("biphenyl.sdf"))
        OpenFF().run(molecule=mol)
        # set the parameter tags
        for term in terms:
            f_group = getattr(mol, force_group)
            parameter = f_group[term]
            parameter.attributes = {"test tag"}
        # make the force field
        ff = mol._build_forcefield()
        classes = [[
            f"{mol.atoms[i].atomic_symbol}{mol.atoms[i].atom_index}"
            for i in term
        ] for term in terms]
        term_length = len(terms[0])
        # now search through and make sure the force groups were tagged
        for group in ff.iter(tag=ff_group):
            for ff_term in group.iter(tag=key):
                ff_class = [
                    ff_term.get(f"class{i}")
                    for i in range(1, 1 + term_length)
                ]
                if ff_class in classes:
                    assert ff_term.get("parametrize") == "test tag"
                else:
                    assert ff_term.get("parametrize", None) is None
def test_parameter_engines(tmpdir, parameter_engine, openff, antechamber):
    """
    Make sure we can parametrise a molecule using antechamber
    """
    if parameter_engine == "openff":
        engine = openff
    else:
        engine = antechamber

    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.sdf"))

        # make sure we have no starting parameters
        assert mol.BondForce.n_parameters == 0
        assert mol.AngleForce.n_parameters == 0
        assert mol.TorsionForce.n_parameters == 0
        assert mol.ImproperTorsionForce.n_parameters == 0
        assert mol.NonbondedForce.n_parameters == 0

        engine.run(mol)
        # make sure the parameters have been set
        assert mol.BondForce.n_parameters != 0
        assert mol.AngleForce.n_parameters != 0
        assert mol.TorsionForce.n_parameters != 0
        assert mol.ImproperTorsionForce.n_parameters != 0
        assert mol.NonbondedForce.n_parameters != 0
def test_rb_energy_round_trip(tmpdir):
    """
    Make sure that no parameters are lost when reading in  RBterms.
    """
    with tmpdir.as_cwd():
        # load the molecule and parameterise
        mol = Ligand.from_file(file_name=get_data("cyclohexane.sdf"))
        XML().run(molecule=mol, input_files=[get_data("cyclohexane.xml")])
        # load the serialised system we extract the parameters from as our reference
        ref_system = XmlSerializer.deserializeSystem(
            open("serialised.xml").read())
        parm_top = load_topology(mol.to_openmm_topology(),
                                 system=ref_system,
                                 xyz=mol.openmm_coordinates())
        ref_energy = energy_decomposition_system(parm_top,
                                                 ref_system,
                                                 platform="Reference")
        # now we need to build the system from our stored parameters
        mol.write_parameters(file_name="test.xml")
        ff = app.ForceField("test.xml")
        qube_system = ff.createSystem(mol.to_openmm_topology())
        with open("qube.xml", "w") as xml_out:
            xml_out.write(XmlSerializer.serialize(qube_system))
        qube_struc = load_topology(mol.to_openmm_topology(),
                                   system=qube_system,
                                   xyz=mol.openmm_coordinates())
        qube_energy = energy_decomposition_system(qube_struc,
                                                  qube_system,
                                                  platform="Reference")
        # compare the decomposed energies of the groups
        for force_group, energy in ref_energy:
            for qube_force, qube_e in qube_energy:
                if force_group == qube_force:
                    assert energy == pytest.approx(qube_e, abs=2e-3)
Exemple #5
0
def test_to_rdkit(molecule):
    """
    Make sure we can convert to rdkit.
    We test on bace which has a chiral center and 12-dichloroethene which has a stereo bond.
    """
    from rdkit import Chem

    mol = Ligand.from_file(file_name=get_data(molecule))
    rd_mol = mol.to_rdkit()
    # make sure the atom and bond stereo match
    for atom in rd_mol.GetAtoms():
        qb_atom = mol.atoms[atom.GetIdx()]
        assert atom.GetIsAromatic() is qb_atom.aromatic
        if qb_atom.stereochemistry is not None:
            if qb_atom.stereochemistry == "S":
                assert atom.GetChiralTag() == Chem.CHI_TETRAHEDRAL_CCW
            else:
                assert atom.GetChiralTag() == Chem.CHI_TETRAHEDRAL_CW
    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()
        if qb_bond.stereochemistry is not None:
            if qb_bond.stereochemistry == "E":
                assert bond.GetStereo() == Chem.BondStereo.STEREOE
            else:
                assert bond.GetStereo() == Chem.BondStereo.STEREOZ
Exemple #6
0
def test_parse_output(driver):
    """
    Test reading gaussian outfiles and extracting the correct information based on the
    driver type.
    """
    outfiles = {}
    with open(get_data("gaussian.log")) as log:
        outfiles["gaussian.log"] = log.read()
    with open(get_data("gaussian.fchk")) as fchk:
        outfiles["lig.fchk"] = fchk.read()

    # build the input
    mol = Ligand.from_file(file_name=get_data("acetone.pdb"))
    # build the atomic model
    qc_spec = qcel.models.common_models.Model(method="pbe", basis="6-31G")
    # build a job for a specific driver
    qc_task = qcel.models.AtomicInput(molecule=mol.to_qcschema(),
                                      driver=driver,
                                      model=qc_spec)
    g = GaussianHarness()
    result = g.parse_output(outfiles=outfiles, input_model=qc_task)
    if driver == "energy":
        assert result.return_result == -1.931393770857046e02
    elif driver == "gradient":
        assert result.return_result.shape == (10, 3)
    elif driver == "hessian":
        assert result.return_result.shape == (30, 30)
Exemple #7
0
def test_no_dihedrals():
    """
    Make sure we return None when no dihedrals are found in the molecule.
    """
    mol = Ligand.from_file(file_name=get_data("water.pdb"))
    assert not mol.dihedrals
    assert mol.n_dihedrals == 0
Exemple #8
0
def test_combine_molecules_sites_deepdiff(openff, xml, acetone, rfree_data, tmpdir):
    """
    Test combining molecules with virtual sites and ensure they are correctly applied and the energy break down matches.
    """
    with tmpdir.as_cwd():
        openff.run(acetone)
        acetone_ref_system = xmltodict.parse(open("serialised.xml").read())
        pyridine = Ligand.from_file(file_name=get_data("pyridine.sdf"))
        xml.run(molecule=pyridine, input_files=[get_data("pyridine.xml")])
        pyridine_ref_system = xmltodict.parse(open("serialised.xml").read())

        combined_xml = _combine_molecules(
            molecules=[acetone, pyridine], parameters=elements, rfree_data=rfree_data
        ).getroot()
        messy = ET.tostring(combined_xml, "utf-8")

        pretty_xml = parseString(messy).toprettyxml(indent="")
        print(pretty_xml)
        with open("combined.xml", "w") as xml_doc:
            xml_doc.write(pretty_xml)
        root = combined_xml.find("QUBEKit")
        assert qubekit.__version__ == root.get("Version")

        # load up new systems and compare
        combinded_ff = app.ForceField("combined.xml")

        acetone_combine_system = xmltodict.parse(
            XmlSerializer.serialize(
                combinded_ff.createSystem(
                    acetone.to_openmm_topology(),
                    nonbondedCutoff=0.9,
                    removeCMMotion=False,
                )
            )
        )
        # slight differences in masses we need to ignore
        acetone_diff = DeepDiff(
            acetone_ref_system,
            acetone_combine_system,
            ignore_order=True,
            significant_digits=6,
            exclude_regex_paths="mass",
        )
        assert len(acetone_diff) == 0
        # add v-site
        pyridine_mod = app.Modeller(
            pyridine.to_openmm_topology(), pyridine.openmm_coordinates()
        )
        pyridine_mod.addExtraParticles(combinded_ff)
        pyridine_combine_system = xmltodict.parse(
            XmlSerializer.serialize(combinded_ff.createSystem(pyridine_mod.topology))
        )
        pyridine_diff = DeepDiff(
            pyridine_ref_system,
            pyridine_combine_system,
            ignore_order=True,
            significant_digits=6,
            exclude_regex_paths="mass",
        )
        assert len(pyridine_diff) == 0
Exemple #9
0
def test_no_impropers():
    """
    Make sure we return None when no impropers are found in the molecule.
    """
    mol = Ligand.from_file(file_name=get_data("water.pdb"))
    assert mol.improper_torsions is None
    assert mol.n_improper_torsions == 0
Exemple #10
0
def test_lennard_jones612(tmpdir):
    """
    Make sure that we can reproduce some reference values using the LJ612 class
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("chloromethane.pdb"))
        # get some initial Nonbonded values
        OpenFF().run(molecule=mol)
        # get some aim reference data
        ExtractChargeData.extract_charge_data_chargemol(molecule=mol,
                                                        dir_path=get_data(""),
                                                        ddec_version=6)
        # apply symmetry to the reference data
        DDECCharges.apply_symmetrisation(molecule=mol)
        # calculate the new LJ terms
        LennardJones612(
            lj_on_polar_h=False,
            # qubekit 1 legacy parameters
            free_parameters={
                "H": h_base(r_free=1.64),
                "C": c_base(r_free=2.08),
                "Cl": cl_base(r_free=1.88),
            },
        ).run(molecule=mol)
        # make sure we get out expected reference values
        assert mol.NonbondedForce[(0, )].sigma == 0.3552211069814666
        assert mol.NonbondedForce[(0, )].epsilon == 0.25918723101839924
        assert mol.NonbondedForce[(1, )].sigma == 0.33888067968663566
        assert mol.NonbondedForce[(1, )].epsilon == 0.9650542683335082
        assert mol.NonbondedForce[(2, )].sigma == 0.22192905304751342
        assert mol.NonbondedForce[(2, )].epsilon == 0.15047278650152818
Exemple #11
0
def test_get_initial_state(tmpdir, starting_conformations):
    """
    Make sure we can correctly build a starting state using the torsiondrive api.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("ethane.sdf"))
        bond = mol.find_rotatable_bonds()[0]
        dihedral = mol.dihedrals[bond.indices][0]
        tdriver = TorsionDriver(starting_conformations=starting_conformations)
        # make the scan data
        dihedral_data = TorsionScan(torsion=dihedral, scan_range=(-165, 180))
        td_state = tdriver._create_initial_state(molecule=mol,
                                                 dihedral_data=dihedral_data,
                                                 qc_spec=QCOptions())
        assert td_state["dihedrals"] == [
            dihedral,
        ]
        assert td_state["elements"] == [
            atom.atomic_symbol for atom in mol.atoms
        ]
        assert td_state["dihedral_ranges"] == [
            (-165, 180),
        ]
        assert np.allclose((mol.coordinates * constants.ANGS_TO_BOHR),
                           td_state["init_coords"][0])
        # make sure we have tried to generate conformers
        assert len(td_state["init_coords"]) <= tdriver.starting_conformations
Exemple #12
0
def test_chargemol_template(tmpdir, version):
    """
    Make sure we can correctly render a chargemol template job.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("water.pdb"))
        OpenFF().parametrise_molecule(molecule=mol)
        charge_method = DDECCharges(
            apply_symmetry=True,
            basis="sto-3g",
            method="hf",
            cores=1,
            memory=1,
            ddec_version=version,
        )
        # fake the chargemol dir
        os.environ["CHARGEMOL_DIR"] = "test"
        # now render the template
        charge_method._build_chargemol_input(density_file_name="test.wfx",
                                             molecule=mol)
        with open("job_control.txt") as job_file:
            job_data = job_file.readlines()

        assert f"DDEC{version}\n" in job_data
        assert "test.wfx\n" in job_data
        assert "test/atomic_densities/\n" in job_data
        assert f"{mol.charge}\n" in job_data
Exemple #13
0
def test_single_point_energy(program, basis, method, tmpdir):
    """
    Make sure our qcengine wrapper works correctly.
    """
    if program not in qcengine.list_available_programs():
        pytest.skip(f"{program} missing skipping test.")

    with tmpdir.as_cwd():
        mol = Ligand.from_file(file_name=get_data("water.pdb"))
        engine = QCEngine(
            program=program,
            basis=basis,
            method=method,
            memory=1,
            cores=1,
            driver="energy",
        )
        result = engine.call_qcengine(molecule=mol)
        assert result.driver == "energy"
        assert result.model.basis == basis
        assert result.model.method == method
        assert result.provenance.creator.lower() == program
        # make sure the grid was set to ultrafine for psi4
        if program == "psi4":
            assert result.keywords["dft_spherical_points"] == 590
            assert result.keywords["dft_radial_points"] == 99
Exemple #14
0
def test_full_tdrive(tmpdir, workers, capsys):
    """
    Try and run a full torsiondrive for ethane with a cheap rdkit method.
    """
    with tmpdir.as_cwd():

        ethane = Ligand.from_file(get_data("ethane.sdf"))
        # make the scan data
        bond = ethane.find_rotatable_bonds()[0]
        dihedral = ethane.dihedrals[bond.indices][0]
        dihedral_data = TorsionScan(torsion=dihedral, scan_range=(-165, 180))
        qc_spec = QCOptions(program="rdkit", basis=None, method="uff")
        local_ops = LocalResource(cores=workers, memory=2)
        tdriver = TorsionDriver(
            n_workers=workers,
            grid_spacing=60,
        )
        _ = tdriver.run_torsiondrive(
            molecule=ethane,
            dihedral_data=dihedral_data,
            qc_spec=qc_spec,
            local_options=local_ops,
        )
        captured = capsys.readouterr()
        # make sure a fresh torsiondrive is run
        assert "Starting new torsiondrive" in captured.out
Exemple #15
0
def test_find_rotatable_bonds_n_rotatables(molecule, n_rotatables):
    """
    Ensure the number of rotatable bonds found matches the expected.
    """
    mol = Ligand.from_file(get_data(molecule))
    assert (len(mol.find_rotatable_bonds(["[*:1]-[CH3:2]",
                                          "[*:1]-[NH2:2]"])) == n_rotatables)
Exemple #16
0
def test_find_rotatable_bonds_no_rotatables(molecule):
    """
    Ensure rigid molecules, or molecules without any rotatable bonds
    do not have any rotatable bonds.
    """
    mol = Ligand.from_file(get_data(molecule))
    assert mol.find_rotatable_bonds(["[*:1]-[CH3:2]", "[*:1]-[NH2:2]"]) is None
Exemple #17
0
def test_optimise_grid_point_and_update(tmpdir, ethane_state):
    """
    Try and perform a single grid point optimisation.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("ethane.sdf"))
        tdriver = TorsionDriver(n_workers=1)
        qc_spec = QCOptions(program="rdkit", basis=None, method="uff")
        local_ops = LocalResource(cores=1, memory=1)
        geo_opt = tdriver._build_geometry_optimiser()
        # get the job inputs
        new_jobs = tdriver._get_new_jobs(td_state=ethane_state)
        coords = new_jobs["-60"][0]
        result = optimise_grid_point(
            geometry_optimiser=geo_opt,
            qc_spec=qc_spec,
            local_options=local_ops,
            molecule=mol,
            coordinates=coords,
            dihedral=ethane_state["dihedrals"][0],
            dihedral_angle=-60,
            job_id=0,
        )
        new_state = tdriver._update_state(
            td_state=ethane_state,
            result_data=[
                result,
            ],
        )
        next_jobs = tdriver._get_new_jobs(td_state=new_state)
        assert "-75" in next_jobs
        assert "-45" in next_jobs
Exemple #18
0
def test_gaussian_solvent_template():
    """
    Make sure that the template rendered with solvent settings matches what we expect.
    """
    mol = Ligand.from_file(get_data("water.pdb"))
    # get the charge method and implicit solvent engine
    charge_engine = DDECCharges()
    solvent_settings = charge_engine.solvent_settings.format_keywords()
    # now make an atomic input for the harness
    task = AtomicInput(
        molecule=mol.to_qcschema(),
        driver="energy",
        model={
            "method": "b3lyp-d3bj",
            "basis": "6-311G"
        },
        keywords=solvent_settings,
    )
    # we need the harness as this will render the template
    gaussian_harness = GaussianHarness()
    config = get_config(local_options={"ncores": 1, "memory": 1})
    job_inputs = gaussian_harness.build_input(task, config)
    # make sure the job file matches or expected reference
    with open(get_data("gaussian_solvent_example.com")) as g_out:
        assert g_out.read() == job_inputs["infiles"]["gaussian.com"]
Exemple #19
0
def test_find_rotatable_bonds_indices_of_bonds():
    mol = Ligand.from_file(get_data("bace0.pdb"))
    rotatables = mol.find_rotatable_bonds(["[*:1]-[CH3:2]", "[*:1]-[NH2:2]"])
    bonds = [(bond.atom1_index, bond.atom2_index) for bond in rotatables]
    expected_bonds = [(12, 13), (5, 13)]
    for bond in bonds:
        assert bond in expected_bonds or tuple(
            reversed(bond)) in expected_bonds
Exemple #20
0
def test_to_topology(molecule):
    """
    Make sure that a topology generated using qubekit matches an openff one.
    """
    mol = Ligand.from_file(file_name=get_data(molecule))
    offmol = OFFMolecule.from_file(file_path=get_data(molecule))
    assert (nx.algorithms.isomorphism.is_isomorphic(
        mol.to_topology(), offmol.to_networkx()) is True)
Exemple #21
0
def test_add_conformers(file_name):
    """
    Load up the bace pdb and then add conformers to it from other file types.
    """
    mol = Ligand.from_file(file_name=get_data("bace0.pdb"))
    mol.coordinates = None
    mol.add_conformer(file_name=get_data(file_name))
    assert mol.coordinates.shape == (mol.n_atoms, 3)
Exemple #22
0
def test_ligand_from_file(file_name):
    """
    For the given file type make sure rdkit can parse it and return the molecule.
    """
    mol = Ligand.from_file(file_name=get_data(file_name))
    assert mol.n_atoms > 1
    assert mol.n_bonds > 1
    assert mol.name is not None
Exemple #23
0
def test_make_unique_names():
    """
    After loading a molecule with non unique atom names make sure a unique set is automatically generated.
    """
    # load the molecule with missing names
    mol = Ligand.from_file(get_data("missing_names.pdb"))
    # make sure they have been converted
    assert mol.has_unique_atom_names is True
def test_improper_round_trip_antechamber(tmpdir, antechamber):
    """
    Make sure that improper torsions are correctly round tripped.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("benzene.sdf"))
        # assign new parameters
        antechamber.run(molecule=mol)
        # make sure we have some 6 impropers
        assert mol.ImproperTorsionForce.n_parameters == 6
        # now write out the parameters
        mol.write_parameters(file_name="test.xml")
        # now load a new molecule
        mol2 = Ligand.from_file(get_data("benzene.sdf"))
        assert mol2.TorsionForce.n_parameters == 0
        XML().run(molecule=mol2, input_files=["test.xml"])
        # make sure we have the same 18 impropers
        assert mol2.ImproperTorsionForce.n_parameters == 6
Exemple #25
0
def test_to_rdkit_no_aromatics():
    """
    Make sure aromatic bonds/atoms are correctly tagged.
    """
    mol = Ligand.from_file(get_data("12-dichloroethene.sdf"))
    rd_mol = mol.to_rdkit()
    for atom in rd_mol.GetAtoms():
        assert atom.GetIsAromatic() is False
    for bond in rd_mol.GetBonds():
        assert bond.GetIsAromatic() is False
Exemple #26
0
def test_parametrise_missing_file(tmpdir):
    """
    If a missing file is provided make sure an error is raised.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("acetone.pdb"))
        mol.home = os.getcwd()
        mol.parameter_engine = "xml"
        with pytest.raises(FileNotFoundError):
            _ = Execute.parametrise(molecule=mol, verbose=False)
Exemple #27
0
def test_to_mapped_smiles():
    """
    Make sure the the mapped smiles flag is respected.
    """
    mol = Ligand.from_file(file_name=get_data("bace0.sdf"))
    no_map = mol.to_smiles(isomeric=True,
                           explicit_hydrogens=True,
                           mapped=False)
    mapped = mol.to_smiles(isomeric=True, explicit_hydrogens=True, mapped=True)
    assert no_map != mapped
Exemple #28
0
def test_no_dihedrals(tmpdir):
    """
    Make sure no torsion drives are run when they are all filtered.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("ethane.sdf"))
        t_scan = TorsionScan1D()
        result_mol = t_scan.run(molecule=mol)
        assert result_mol.qm_scans is None
        assert np.allclose(result_mol.coordinates, mol.coordinates)
def test_rb_offxml(tmpdir):
    """Make sure an error is raised if we try to create an offxml with a RB torsion."""
    with tmpdir.as_cwd():
        mol = Ligand.from_file(file_name=get_data("cyclohexane.sdf"))
        XML().run(molecule=mol, input_files=[get_data("cyclohexane.xml")])
        # there should be 6 RB terms
        assert mol.RBTorsionForce.n_parameters == 6

        with pytest.raises(NotImplementedError):
            mol.to_offxml("test.offxml")
Exemple #30
0
def biphenyl():
    """
    Load up a biphenyl molecule with some torsiondrive data.
    """
    # load biphenyl
    mol = Ligand.from_file(file_name=get_data("biphenyl.sdf"))
    # load the torsiondrive data
    td_data = TorsionDriveData.from_qdata(
        qdata_file=get_data("biphenyl_qdata.txt"), dihedral=(6, 10, 11, 8))
    mol.add_qm_scan(scan_data=td_data)
    return mol