def run_json_qcschema(json_data, clean, json_serialization, keep_wfn=False): """ An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4. Parameters ---------- json_data : JSON Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema. Examples -------- """ # Clean a few things _clean_psi_environ(clean) # This is currently a forced override if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]: json_data["schema_name"] = "qcschema_input" else: raise KeyError("Schema name of '{}' not understood".format( json_data["schema_name"])) if json_data["schema_version"] != 1: raise KeyError("Schema version of '{}' not understood".format( json_data["schema_version"])) if json_data.get("nthreads", False) is not False: core.set_num_threads(json_data["nthreads"], quiet=True) # Build molecule if "schema_name" in json_data["molecule"]: molschemus = json_data["molecule"] # dtype >=2 else: molschemus = json_data # dtype =1 mol = core.Molecule.from_schema(molschemus) # Update molecule geometry as we orient and fix_com json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist() # Set options kwargs = json_data["keywords"].pop("function_kwargs", {}) p4util.set_options(json_data["keywords"]) # Setup the computation method = json_data["model"]["method"] core.set_global_option("BASIS", json_data["model"]["basis"]) kwargs.update({"return_wfn": True, "molecule": mol}) # Handle special properties case if json_data["driver"] == "properties": if "properties" not in kwargs: kwargs["properties"] = list(default_properties_) # Actual driver run val, wfn = methods_dict_[json_data["driver"]](method, **kwargs) # Pull out a standard set of SCF properties if "extras" not in json_data: json_data["extras"] = {} json_data["extras"]["qcvars"] = {} current_qcvars_only = json_data["extras"].get("current_qcvars_only", False) if json_data["extras"].get("wfn_qcvars_only", False): psi_props = wfn.variables( include_deprecated_keys=(not current_qcvars_only)) else: psi_props = core.variables( include_deprecated_keys=(not current_qcvars_only)) for k, v in psi_props.items(): if k not in json_data["extras"]["qcvars"]: json_data["extras"]["qcvars"][k] = _serial_translation( v, json=json_serialization) # Still a bit of a mess at the moment add in local vars as well. for k, v in wfn.variables().items(): if k not in json_data["extras"]["qcvars"]: # interpreting wfn_qcvars_only as no deprecated qcvars either if not (json_data["extras"].get("wfn_qcvars_only", False) and (any([ k.upper().endswith(" DIPOLE " + cart) for cart in ["X", "Y", "Z"] ]) or any([ k.upper().endswith(" QUADRUPOLE " + cart) for cart in ["XX", "YY", "ZZ", "XY", "XZ", "YZ"] ]) or k.upper() in [ "SOS-MP2 CORRELATION ENERGY", "SOS-MP2 TOTAL ENERGY", "SOS-PI-MP2 CORRELATION ENERGY", "SOS-PI-MP2 TOTAL ENERGY", "SCS-MP3 CORRELATION ENERGY", "SCS-MP3 TOTAL ENERGY", ])): json_data["extras"]["qcvars"][k] = _serial_translation( v, json=json_serialization) # Handle the return result if json_data["driver"] == "energy": json_data["return_result"] = val elif json_data["driver"] in ["gradient", "hessian"]: json_data["return_result"] = _serial_translation( val, json=json_serialization) elif json_data["driver"] == "properties": ret = {} mtd = json_data["model"]["method"].upper() # Dipole/quadrupole still special case if "dipole" in kwargs["properties"]: ret["dipole"] = _serial_translation(psi_props[mtd + " DIPOLE"], json=json_serialization) if "quadrupole" in kwargs["properties"]: ret["quadrupole"] = _serial_translation(psi_props[mtd + " QUADRUPOLE"], json=json_serialization) ret.update( _convert_variables(wfn.variables(), context="properties", json=json_serialization)) json_data["return_result"] = ret else: raise KeyError("Did not understand Driver key %s." % json_data["driver"]) props = { "calcinfo_nbasis": wfn.nso(), "calcinfo_nmo": wfn.nmo(), "calcinfo_nalpha": wfn.nalpha(), "calcinfo_nbeta": wfn.nbeta(), "calcinfo_natom": mol.geometry().shape[0], "nuclear_repulsion_energy": mol.nuclear_repulsion_energy( ), # use this b/c psivar is monomer for SAPT } props.update( _convert_variables(psi_props, context="generics", json=json_serialization)) if not list( set(['CBS NUMBER', 'NBODY NUMBER', 'FINDIF NUMBER']) & set(json_data["extras"]["qcvars"].keys())): props.update( _convert_variables(psi_props, context="scf", json=json_serialization)) # Write out post-SCF keywords if "MP2 CORRELATION ENERGY" in psi_props: props.update( _convert_variables(psi_props, context="mp2", json=json_serialization)) if "CCSD CORRELATION ENERGY" in psi_props: props.update( _convert_variables(psi_props, context="ccsd", json=json_serialization)) if "CCSD(T) CORRELATION ENERGY" in psi_props: props.update( _convert_variables(psi_props, context="ccsd(t)", json=json_serialization)) json_data["properties"] = props json_data["success"] = True json_data["provenance"]["module"] = wfn.module() if keep_wfn: json_data["wavefunction"] = _convert_wavefunction(wfn) files = { "psi4.grad": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".grad"), "psi4.hess": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".hess"), # binary "psi4.180.npy": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".180.npy"), "timer.dat": Path( "timer.dat" ), # ok for `psi4 --qcschema` but no file collected for `qcengine.run_program(..., "psi4")` } json_data["native_files"] = { fl: flpath.read_text() for fl, flpath in files.items() if flpath.exists() } # Reset state _clean_psi_environ(clean) json_data["schema_name"] = "qcschema_output" return json_data
def run_json_qcschema(json_data, clean, json_serialization, keep_wfn=False): """ An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4. Parameters ---------- json_data : JSON Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema. Examples -------- """ # Clean a few things _clean_psi_environ(clean) # This is currently a forced override if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]: json_data["schema_name"] = "qcschema_input" else: raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"])) if json_data["schema_version"] != 1: raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"])) if json_data.get("nthreads", False) is not False: core.set_num_threads(json_data["nthreads"], quiet=True) # Build molecule if "schema_name" in json_data["molecule"]: molschemus = json_data["molecule"] # dtype >=2 else: molschemus = json_data # dtype =1 mol = core.Molecule.from_schema(molschemus) # Update molecule geometry as we orient and fix_com json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist() # Set options kwargs = json_data["keywords"].pop("function_kwargs", {}) p4util.set_options(json_data["keywords"]) # Setup the computation method = json_data["model"]["method"] core.set_global_option("BASIS", json_data["model"]["basis"]) kwargs.update({"return_wfn": True, "molecule": mol}) # Handle special properties case if json_data["driver"] == "properties": if "properties" in json_data["model"]: kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]] extra = set(kwargs["properties"]) - can_do_properties_ if len(extra): raise KeyError("Did not understand property key %s." % kwargs["properties"]) else: kwargs["properties"] = list(can_do_properties_) # Actual driver run val, wfn = methods_dict_[json_data["driver"]](method, **kwargs) # Pull out a standard set of SCF properties if "extras" not in json_data: json_data["extras"] = {} json_data["extras"]["qcvars"] = {} if json_data["extras"].get("wfn_qcvars_only", False): psi_props = wfn.variables() else: psi_props = core.variables() for k, v in psi_props.items(): if k not in json_data["extras"]["qcvars"]: json_data["extras"]["qcvars"][k] = _serial_translation(v, json=json_serialization) # Still a bit of a mess at the moment add in local vars as well. for k, v in wfn.variables().items(): if k not in json_data["extras"]["qcvars"]: json_data["extras"]["qcvars"][k] = _serial_translation(v, json=json_serialization) # Handle the return result if json_data["driver"] == "energy": json_data["return_result"] = val elif json_data["driver"] in ["gradient", "hessian"]: json_data["return_result"] = _serial_translation(val, json=json_serialization) elif json_data["driver"] == "properties": ret = {} mtd = json_data["model"]["method"].upper() # Dipole/quadrupole still special case if "dipole" in kwargs["properties"]: ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]] if "quadrupole" in kwargs["properties"]: ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]] ret.update(_convert_variables(wfn.variables(), context="properties", json=json_serialization)) json_data["return_result"] = ret else: raise KeyError("Did not understand Driver key %s." % json_data["driver"]) props = { "calcinfo_nbasis": wfn.nso(), "calcinfo_nmo": wfn.nmo(), "calcinfo_nalpha": wfn.nalpha(), "calcinfo_nbeta": wfn.nbeta(), "calcinfo_natom": mol.geometry().shape[0], } props.update(_convert_variables(psi_props, context="generics", json=json_serialization)) if not list(set(['CBS NUMBER', 'NBODY NUMBER', 'FINDIF NUMBER']) & set(json_data["extras"]["qcvars"].keys())): props.update(_convert_variables(psi_props, context="scf", json=json_serialization)) # Write out post-SCF keywords if "MP2 CORRELATION ENERGY" in psi_props: props.update(_convert_variables(psi_props, context="mp2", json=json_serialization)) if "CCSD CORRELATION ENERGY" in psi_props: props.update(_convert_variables(psi_props, context="ccsd", json=json_serialization)) if "CCSD(T) CORRELATION ENERGY" in psi_props: props.update(_convert_variables(psi_props, context="ccsd(t)", json=json_serialization)) json_data["properties"] = props json_data["success"] = True if keep_wfn: json_data["wavefunction"] = _convert_wavefunction(wfn) # Reset state _clean_psi_environ(clean) json_data["schema_name"] = "qcschema_output" return json_data