Beispiel #1
0
    def _validate_specification(self) -> None:
        """
        Validate the specification this is called before running an optimisation to catch errors before run time.
        """
        from openff.toolkit.typing.engines.smirnoff import get_available_force_fields

        openff_forcefields = [
            ff.split(".offxml")[0].lower() for ff in get_available_force_fields()
        ]
        # set up some models
        ani_methods = {"ani1x", "ani1ccx", "ani2x"}
        xtb_methods = {
            "gfn0-xtb",
            "gfn0xtb",
            "gfn1-xtb",
            "gfn1xtb",
            "gfn2-xtb",
            "gfn2xtb",
            "gfn-ff",
            "gfnff",
        }
        rdkit_methods = {"uff", "mmff94", "mmff94s"}
        gaff_forcefields = {
            "gaff-1.4",
            "gaff-1.8",
            "gaff-1.81",
            "gaff-2.1",
            "gaff-2.11",
        }
        settings = {
            "openmm": {"antechamber": gaff_forcefields, "smirnoff": openff_forcefields},
            "torchani": {None: ani_methods},
            "xtb": {None: xtb_methods},
            "rdkit": {None: rdkit_methods},
        }
        # now check these settings
        # TODO do we raise an error or just change at run time with a warning?
        if self.program.lower() != "psi4" and self.optimiser == "optking":
            raise SpecificationError(
                f"The optimiser optking currently only supports psi4 as the engine."
            )

        # we do not validate QM as there are so many options
        if self.program.lower() in settings:
            program_settings = settings[self.program.lower()]

            allowed_methods = program_settings.get(self.basis, None)
            if allowed_methods is None:
                raise SpecificationError(
                    f"The Basis {self.basis} is not supported for the program {self.program} please chose from {program_settings.keys()}"
                )
            # now check the method
            method = self.method.split(".offxml")[0].lower()
            if method not in allowed_methods:
                raise SpecificationError(
                    f"The method {method} is not available for the program {self.program}  with basis {self.basis}, please chose from {allowed_methods}"
                )
Beispiel #2
0
 def validate_optimiser(cls, optimiser: str) -> str:
     """
     Make sure the chosen optimiser is available.
     """
     procedures = qcng.list_available_procedures()
     if optimiser.lower() not in procedures:
         raise SpecificationError(
             f"The optimiser {optimiser} is not available, available optimisers are {procedures}"
         )
     return optimiser.lower()
Beispiel #3
0
    def _check_solvent(cls, solvent: str) -> str:
        """
        Make sure that a valid solvent from the list of supported values is passed.
        """

        solvent_formula = cls._solvents.get(solvent.lower(), solvent.upper())
        if solvent_formula not in cls._solvents.values():
            raise SpecificationError(
                f"The solvent {solvent} is not supported please chose from the following solvents or formulas {cls._solvents.items()}"
            )
        return solvent_formula
Beispiel #4
0
    def validate_program(self):
        """
        Validate the choice of program against those supported by QCEngine and QUBEKit.
        """
        programs = qcng.list_available_programs()
        programs.discard("dftd3")

        if self.program.lower() not in programs:
            raise SpecificationError(
                f"The program {self.program} is not available, available programs are {programs}"
            )
Beispiel #5
0
    def _validate_specification(self, qc_spec: "QCOptions") -> None:
        """
        Validate the specification this is called before running an optimisation to catch errors before run time.
        """

        # now check these settings
        # TODO do we raise an error or just change at run time with a warning?
        if qc_spec.program.lower() != "psi4" and self.optimiser.lower() == "optking":
            raise SpecificationError(
                "The optimiser optking currently only supports psi4 as the engine."
            )
Beispiel #6
0
    def _check_forcefield(cls, force_field: str) -> str:
        """
        Make sure the supplied force field is valid.
        """

        openff_forcefields = [
            ff.lower() for ff in get_available_force_fields()
        ]
        if force_field in openff_forcefields:
            return force_field.lower()
        else:
            raise SpecificationError(
                f"The force field {force_field} was not found by the openff-toolkit please chosse from {openff_forcefields}."
            )
Beispiel #7
0
 def is_available(cls) -> bool:
     """
     The MBIS option is only available via new psi4 so make sure it is installed.
     """
     # check installed
     psi4 = which_import(
         "psi4",
         return_bool=True,
         raise_error=True,
         raise_msg="Please install via `conda install psi4 -c psi4`.",
     )
     # now check the version meets the minimum requirement
     which_psi4 = which("psi4")
     with popen([which_psi4, "--version"]) as exc:
         exc["proc"].wait(timeout=30)
     version = parse_version(safe_version(exc["stdout"].split()[-1]))
     if version <= parse_version("1.4a1"):
         raise SpecificationError(
             f"The version of psi4 installed is {version} and needs to be 1.4 or newer please update it to continue."
         )
     return psi4
Beispiel #8
0
    def validate_specification(self) -> None:
        """
        Validate the specification this should be called before using the spec to find errors.
        """
        # make sure the program is valid first then the basis method combination
        self.validate_program()

        openff_forcefields = [
            ff.split(".offxml")[0].lower()
            for ff in get_available_force_fields()
        ]
        # set up some models
        ani_methods = {"ani1x", "ani1ccx", "ani2x"}
        xtb_methods = {
            "gfn0-xtb",
            "gfn0xtb",
            "gfn1-xtb",
            "gfn1xtb",
            "gfn2-xtb",
            "gfn2xtb",
            "gfn-ff",
            "gfnff",
        }
        rdkit_methods = {"uff", "mmff94", "mmff94s"}
        gaff_forcefields = {
            "gaff-1.4",
            "gaff-1.8",
            "gaff-1.81",
            "gaff-2.1",
            "gaff-2.11",
        }
        settings = {
            "openmm": {
                "antechamber": gaff_forcefields,
                "smirnoff": openff_forcefields
            },
            "torchani": {
                None: ani_methods
            },
            "xtb": {
                None: xtb_methods
            },
            "rdkit": {
                None: rdkit_methods
            },
        }
        # now check these settings
        # TODO do we raise an error or just change at run time with a warning?
        # we do not validate QM as there are so many options
        if self.program.lower() in settings:
            program_settings = settings[self.program.lower()]

            allowed_methods = program_settings.get(self.basis, None)
            if allowed_methods is None:
                raise SpecificationError(
                    f"The Basis {self.basis} is not supported for the program {self.program} please chose from {program_settings.keys()}"
                )
            # now check the method
            method = self.method.split(".offxml")[0].lower()
            if method not in allowed_methods:
                raise SpecificationError(
                    f"The method {method} is not available for the program {self.program}  with basis {self.basis}, please chose from {allowed_methods}"
                )
        if self.td_settings is not None:
            if self.program.lower() not in ["gaussian"]:
                raise SpecificationError(
                    f"The program {self.program.lower()} does not support time-dependent calculations."
                )