예제 #1
0
    def parse_raw(cls, data: Union[bytes, str], *, encoding: str = None) -> "ProtoModel":  # type: ignore
        """
        Parses raw string or bytes into a Model object.

        Parameters
        ----------
        data : Union[bytes, str]
            A serialized data blob to be deserialized into a Model.
        encoding : str, optional
            The type of the serialized array, available types are: {'json', 'json-ext', 'msgpack-ext', 'pickle'}

        Returns
        -------
        Model
            The requested model from a serialized format.
        """

        if encoding is None:
            if isinstance(data, str):
                encoding = "json"
            elif isinstance(data, bytes):
                encoding = "msgpack-ext"
            else:
                raise TypeError("Input is neither str nor bytes, please specify an encoding.")

        if encoding.endswith(("json", "javascript", "pickle")):
            return super().parse_raw(data, content_type=encoding)
        elif encoding in ["msgpack-ext", "json-ext"]:
            obj = deserialize(data, encoding)
        else:
            raise TypeError(f"Content type '{encoding}' not understood.")

        return cls.parse_obj(obj)
    def prepare(self):
        if self._required_auth:
            self.authenticate(self._required_auth)

        try:
            self.data = deserialize(self.request.body, self.encoding)
        except:
            raise tornado.web.HTTPError(status_code=401,
                                        reason="Could not deserialize body.")
예제 #3
0
    def prepare(self):
        if self._required_auth:
            self.authenticate(self._required_auth)

        try:
            if (self.encoding == "json") and isinstance(
                    self.request.body, bytes):
                blob = self.request.body.decode()
            else:
                blob = self.request.body

            self.data = deserialize(blob, self.encoding)
        except:
            raise tornado.web.HTTPError(status_code=401,
                                        reason="Could not deserialize body.")
예제 #4
0
    def compute(self, input_model: "AtomicInput",
                config: "TaskConfig") -> "AtomicResult":
        """
        Runs Psi4 in API mode
        """
        self.found(raise_error=True)
        pversion = parse_version(self.get_version())

        if pversion < parse_version("1.2"):
            raise ResourceError("Psi4 version '{}' not understood.".format(
                self.get_version()))

        # Location resolution order config.scratch_dir, $PSI_SCRATCH, /tmp
        parent = config.scratch_directory
        if parent is None:
            parent = os.environ.get("PSI_SCRATCH", None)

        error_type = None
        error_message = None
        compute_success = False

        if isinstance(input_model.model.basis, BasisSet):
            raise InputError(
                "QCSchema BasisSet for model.basis not implemented. Use string basis name."
            )

        # Basis must not be None for HF3c
        old_basis = input_model.model.basis
        input_model.model.__dict__["basis"] = old_basis or ""

        with temporary_directory(parent=parent,
                                 suffix="_psi_scratch") as tmpdir:

            caseless_keywords = {
                k.lower(): v
                for k, v in input_model.keywords.items()
            }
            if (input_model.molecule.molecular_multiplicity !=
                    1) and ("reference" not in caseless_keywords):
                input_model.keywords["reference"] = "uhf"

            # Old-style JSON-based command line
            if pversion < parse_version("1.4a2.dev160"):

                # Setup the job
                input_data = input_model.dict(encoding="json")
                input_data["nthreads"] = config.ncores
                input_data["memory"] = int(config.memory * 1024 * 1024 * 1024 *
                                           0.95)  # Memory in bytes
                input_data["success"] = False
                input_data["return_output"] = True

                if input_data["schema_name"] == "qcschema_input":
                    input_data["schema_name"] = "qc_schema_input"

                # Execute the program
                success, output = execute(
                    [
                        which("psi4"), "--scratch", tmpdir, "--json",
                        "data.json"
                    ],
                    {"data.json": json.dumps(input_data)},
                    ["data.json"],
                    scratch_directory=tmpdir,
                )

                output_data = input_data.copy()
                if success:
                    output_data = json.loads(output["outfiles"]["data.json"])
                    if "extras" not in output_data:
                        output_data["extras"] = {}

                    # Check QCVars
                    local_qcvars = output_data.pop("psi4:qcvars", None)
                    if local_qcvars:
                        # Edge case where we might already have qcvars, should not happen
                        if "qcvars" in output_data["extras"]:
                            output_data["extras"][
                                "local_qcvars"] = local_qcvars
                        else:
                            output_data["extras"]["qcvars"] = local_qcvars

                    if output_data.get("success", False) is False:
                        error_message, error_type = self._handle_errors(
                            output_data)
                    else:
                        compute_success = True

                else:
                    error_message = output.get("stderr", "No STDERR output")
                    error_type = "execution_error"

                # Reset the schema if required
                output_data["schema_name"] = "qcschema_output"
                output_data.pop("memory", None)
                output_data.pop("nthreads", None)
                output_data["stdout"] = output_data.pop("raw_output", None)

            else:

                if input_model.extras.get("psiapi", False):
                    import psi4

                    orig_scr = psi4.core.IOManager.shared_object(
                    ).get_default_path()
                    psi4.core.set_num_threads(config.ncores, quiet=True)
                    psi4.set_memory(f"{config.memory}GB", quiet=True)
                    # psi4.core.IOManager.shared_object().set_default_path(str(tmpdir))
                    if pversion < parse_version(
                            "1.4"):  # adjust to where DDD merged
                        # slightly dangerous in that if `qcng.compute({..., psiapi=True}, "psi4")` called *from psi4
                        #   session*, session could unexpectedly get its own files cleaned away.
                        output_data = psi4.schema_wrapper.run_qcschema(
                            input_model).dict()
                    else:
                        output_data = psi4.schema_wrapper.run_qcschema(
                            input_model, postclean=False).dict()
                    # success here means execution returned. output_data may yet be qcel.models.AtomicResult or qcel.models.FailedOperation
                    success = True
                    if output_data.get("success", False):
                        output_data["extras"]["psiapi_evaluated"] = True
                    psi4.core.IOManager.shared_object().set_default_path(
                        orig_scr)
                else:
                    run_cmd = [
                        which("psi4"),
                        "--scratch",
                        str(tmpdir),
                        "--nthread",
                        str(config.ncores),
                        "--memory",
                        f"{config.memory}GB",
                        "--qcschema",
                        "data.msgpack",
                    ]
                    input_files = {
                        "data.msgpack": input_model.serialize("msgpack-ext")
                    }
                    success, output = execute(run_cmd,
                                              input_files, ["data.msgpack"],
                                              as_binary=["data.msgpack"],
                                              scratch_directory=tmpdir)
                    if success:
                        output_data = deserialize(
                            output["outfiles"]["data.msgpack"], "msgpack-ext")
                    else:
                        output_data = input_model.dict()

                if success:
                    if output_data.get("success", False) is False:
                        error_message, error_type = self._handle_errors(
                            output_data)
                    else:
                        compute_success = True
                else:
                    error_message = output.get("stderr", "No STDERR output")
                    error_type = "execution_error"

        # Dispatch errors, PSIO Errors are not recoverable for future runs
        if compute_success is False:

            if "PSIO Error" in error_message:
                if "scratch directory" in error_message:
                    # Psi4 cannot access the folder or file
                    raise ResourceError(error_message)
                else:
                    # Likely a random error, worth retrying
                    raise RandomError(error_message)
            elif ("SIGSEV" in error_message) or (
                    "SIGSEGV" in error_message) or ("segmentation fault"
                                                    in error_message):
                raise RandomError(error_message)
            elif ("TypeError: set_global_option"
                  in error_message) or (error_type == "ValidationError"):
                raise InputError(error_message)
            elif "RHF reference is only for singlets" in error_message:
                raise InputError(error_message)
            else:
                raise UnknownError(error_message)

        # Reset basis
        output_data["model"]["basis"] = old_basis

        # Move several pieces up a level
        output_data["provenance"]["memory"] = round(config.memory, 3)
        output_data["provenance"]["nthreads"] = config.ncores

        # Delete keys
        output_data.pop("return_output", None)

        return AtomicResult(**output_data)