def test_program_not_installed():
    """
    Make sure an error is raised when we try and use a program that is not available.
    """
    g_opt = GeometryOptimiser()
    with pytest.raises(SpecificationError):
        g_opt.program = "test"
예제 #2
0
def test_optimiser_keywords(optimiser):
    """
    For the given optimiser make sure the keywords are updated correctly.
    """
    g = GeometryOptimiser(optimiser=optimiser, maxiter=1, convergence="GAU")
    keywords = g._build_optimiser_keywords(program="psi4")
    assert 1 in keywords.values()
    assert "GAU" in keywords.values()
예제 #3
0
    def _run_qm_opt(
        self,
        molecule: "Ligand",
        conformers: List[np.array],
        qc_spec: QCOptions,
        local_options: LocalResource,
    ) -> "Ligand":
        """
        Run the main QM optimisation on each of the input conformers in order and stop when we get a fully optimised structure.

        Args:
            molecule: The qubekit molecule to run the optimisation on.
            conformers: The list of pre-optimised conformers.
            qc_spec: The QCSpec used to run the QM optimisation.
            local_options: The local resource that is available for the optimisation.
        """
        opt_mol = deepcopy(molecule)
        g_opt = GeometryOptimiser(convergence=self.convergence_criteria,
                                  maxiter=50)

        for i, conformer in enumerate(
                tqdm(conformers,
                     desc="Optimising conformer",
                     total=len(conformers),
                     ncols=80)):
            with folder_setup(folder_name=f"conformer_{i}"):
                # set the coords
                opt_mol.coordinates = conformer
                # errors are auto raised from the class so catch the result, and write to file
                qm_result, result = g_opt.optimise(
                    molecule=opt_mol,
                    allow_fail=True,
                    return_result=True,
                    qc_spec=qc_spec,
                    local_options=local_options,
                )
                if result.success:
                    break
                else:
                    # grab last coords and bump
                    coords = qm_result.coordinates + np.random.choice(
                        a=[0, 0.01], size=(qm_result.n_atoms, 3))
                    opt_mol.coordinates = coords
                    bump_mol, bump_result = g_opt.optimise(
                        molecule=opt_mol,
                        allow_fail=True,
                        return_result=True,
                        local_options=local_options,
                        qc_spec=qc_spec,
                    )
                    if bump_result.success:
                        qm_result = bump_mol
                        break

        else:
            raise GeometryOptimisationError(
                "No molecule conformer could be optimised to GAU TIGHT")
        return qm_result
def test_optimiser_keywords(optimiser):
    """
    For the given optimiser make sure the keywords are updated correctly.
    """
    if "psi4" not in qcengine.list_available_programs():
        pytest.skip("Psi4 missing skipping.")
    g = GeometryOptimiser(
        optimiser=optimiser, maxiter=1, convergence="GAU", program="psi4"
    )
    keywords = g.build_optimiser_keywords()
    assert 1 in keywords.values()
    assert "GAU" in keywords.values()
def test_optmiser_fail_no_output(tmpdir):
    """
    Make sure we raise an error correctly when there is no output from a failed optimisation.
    """
    if "psi4" not in qcengine.list_available_programs():
        pytest.skip("Psi4 missing skipping test.")
    with tmpdir.as_cwd():
        mol = Ligand.from_file(file_name=get_data("water.pdb"))
        g = GeometryOptimiser(
            program="psi4", method="wb97x-dbj", basis="dzvp", maxiter=10
        )
        with pytest.raises(RuntimeError):
            g.optimise(molecule=mol, allow_fail=False)
예제 #6
0
def test_optking_fail():
    """
    Optking currently only works with psi4 make sure we raise an error if we use
    a different program.
    """
    with pytest.raises(SpecificationError):
        mol = Ligand.from_file(file_name=get_data("water.pdb"))
        g = GeometryOptimiser(optimiser="optking")
        g.optimise(
            molecule=mol,
            qc_spec=QCOptions(program="rdkit", basis=None, method="uff"),
            local_options=LocalResource(cores=1, memory=1),
        )
def test_optimise_fail_output(tmpdir):
    """
    Make sure the optimised geometries and result is still wrote out if we fail the molecule and an error is rasied.
    """
    with tmpdir.as_cwd():
        mol = Ligand.from_file(file_name=get_data("water.pdb"))
        g = GeometryOptimiser(
            program="torchani", method="ani1ccx", basis=None, maxiter=5
        )
        with pytest.raises(RuntimeError):
            g.optimise(molecule=mol, allow_fail=False)
        files = os.listdir()
        assert "opt.xyz" in files
        assert "opt_trajectory.xyz" in files
        assert "result.json" in files
def test_spec_validation_pass(program, basis, method):
    """
    Make sure we can correctly validate a specification.
    """
    if program not in qcengine.list_available_programs():
        pytest.skip(f"{program} missing skipping test")
    _ = GeometryOptimiser(program=program, basis=basis, method=method)
def test_optking_fail():
    """
    Optking currently only works with psi4 make sure we raise an error if we use
    a different program.
    """
    with pytest.raises(SpecificationError):
        GeometryOptimiser(optimiser="optking", program="rdkit")
예제 #10
0
def test_spec_validation_fail(program, basis, method):
    """
    Make sure than an invalid specification raises an error.
    """
    if program not in qcengine.list_available_programs():
        pytest.skip(f"{program} missing skipping test")
    with pytest.raises(SpecificationError):
        _ = GeometryOptimiser(program=program, basis=basis, method=method)
예제 #11
0
def test_local_options():
    """
    Make sure the task config is correctly made and keywords are converted.
    """
    g_opt = GeometryOptimiser(cores=10, memory=2)
    local_options = g_opt.local_options
    assert g_opt.cores == local_options["ncores"]
    assert g_opt.memory == local_options["memory"]
예제 #12
0
def test_optimise(program, basis, method, tmpdir):
    """
    Test running different optimisers with different programs.
    """
    if program not in qcengine.list_available_programs():
        pytest.skip(f"{program} missing skipping test.")

    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("water.pdb"))
        g = GeometryOptimiser(
            program=program,
            basis=basis,
            method=method,
            optimiser="geometric",
            convergence="GAU",
        )
        result_mol, _ = g.optimise(molecule=mol, return_result=False)
        assert result_mol.coordinates.tolist() != mol.coordinates.tolist()
예제 #13
0
    def _pre_opt(self, molecule: "Ligand", qc_spec: QCOptions,
                 local_options: LocalResource) -> List[np.array]:
        """Run the pre optimisation stage and return the optimised conformers ready for QM optimisation.

        Args:
            molecule: The qubekit molecule to run the optimisation on.

        Returns:
            A list of final coordinates from the optimisations.
        """
        from multiprocessing import Pool

        g_opt = GeometryOptimiser(convergence="GAU", maxiter=self.maxiter)

        # generate the input conformations, number will include the input conform if provided
        geometries = molecule.generate_conformers(
            n_conformers=self.seed_conformers)
        molecule.to_multiconformer_file(file_name="starting_coords.xyz",
                                        positions=geometries)
        opt_list = []
        with Pool(processes=local_options.cores) as pool:
            for confomer in geometries:
                opt_mol = deepcopy(molecule)
                opt_mol.coordinates = confomer
                opt_list.append(
                    pool.apply_async(
                        g_opt.optimise,
                        (opt_mol, qc_spec, local_options, True, True)))

            results = []
            for result in tqdm(
                    opt_list,
                    desc=
                    f"Optimising conformers with {self.pre_optimisation_method}",
                    total=len(opt_list),
                    ncols=80,
            ):
                # errors are auto raised from the class so catch the result, and write to file
                result_mol, opt_result = result.get()
                if opt_result.success:
                    # save the final energy and molecule
                    results.append((result_mol, opt_result.energies[-1]))
                else:
                    # save the molecule and final energy from the last step if it fails
                    results.append(
                        (result_mol, opt_result.input_data["energies"][-1]))

        # sort the results
        results.sort(key=lambda x: x[1])
        final_geometries = [re[0].coordinates for re in results]
        # write all conformers out
        molecule.to_multiconformer_file(file_name="final_pre_opt_coords.xyz",
                                        positions=final_geometries)
        return final_geometries
예제 #14
0
def test_optimise(qc_spec: QCOptions, tmpdir):
    """
    Test running different optimisers with different programs.
    """
    if qc_spec.program.lower() not in qcengine.list_available_programs():
        pytest.skip(f"{qc_spec.program} missing skipping test.")

    with tmpdir.as_cwd():
        mol = Ligand.from_file(get_data("water.pdb"))
        g = GeometryOptimiser(
            optimiser="geometric",
            convergence="GAU",
        )
        result_mol, _ = g.optimise(
            molecule=mol,
            return_result=False,
            qc_spec=qc_spec,
            local_options=LocalResource(cores=1, memory=1),
        )
        assert result_mol.coordinates.tolist() != mol.coordinates.tolist()
예제 #15
0
def test_missing_optimiser():
    """
    Make sure an error is raised when we try and set a missing optimiser.
    """
    with pytest.raises(SpecificationError):
        _ = GeometryOptimiser(optimiser="bad_optimiser")
예제 #16
0
def test_rdkit_available():
    """
    Make sure the geometry optimiser allows rdkit as this comes with QUBEKit.
    """
    g_opt = GeometryOptimiser()
    g_opt.program = "rdkit"