Source code for mfml_qc.oracles.pyscf

import os
import sys
import json
import subprocess
from typing import Dict, Any, Union
from .base import QuantumEngine


[docs] class PySCFEngine(QuantumEngine): """ Implementation for the PySCF library as the quantum chemsitry engine. This script is untested and is under works. """ def __init__(self, python_executable: str = sys.executable): """ Initializes the PySCF engine. Args: python_executable: Path to the Python executable that has PySCF installed. Defaults to the environment currently running the script. """ self.python_executable = python_executable
[docs] def generate_input( self, geometry: Union[str, tuple], fidelity_params: Dict[str, Any], work_dir: str, ) -> str: os.makedirs(work_dir, exist_ok=True) input_path = os.path.join(work_dir, "run_pyscf.py") method = fidelity_params.get("method", "B3LYP") basis = fidelity_params.get("basis", "def2-SVP") charge = fidelity_params.get("charge", 0) # PySCF uses "spin" (number of unpaired electrons, 2S) # ORCA uses "multiplicity" (2S + 1) multiplicity = fidelity_params.get("multiplicity", 1) spin = multiplicity - 1 # script that executes PySCF and dumps results to JSON. # Prevents PySCF memory leaks script_content = f""" import json from pyscf import gto, scf, dft try: # extract geomtry mol = gto.M( atom='{geometry}', basis='{basis}', charge={charge}, spin={spin}, verbose=3 # Suppress excessive printing ) # method method_name = '{method}'.upper() if method_name == 'HF': mf = scf.RHF(mol) if {spin} == 0 else scf.UHF(mol) else: mf = dft.RKS(mol) if {spin} == 0 else dft.UKS(mol) mf.xc = '{method}' # mf.conv_tol = 1e-8 # Run the calculation energy = mf.kernel() success = mf.converged # Save results results = {{ "success": success, "energy": energy }} except Exception as e: results = {{ "success": False, "error": str(e) }} with open("pyscf_results.json", "w") as f: json.dump(results, f) """ with open(input_path, "w") as f: f.write(script_content.strip()) return input_path
[docs] def run_calculation(self, input_file: str, work_dir: str) -> str: # PySCF output will be dumped to this JSON file by the above generated script output_file = os.path.join(work_dir, "pyscf_results.json") try: subprocess.run( [self.python_executable, input_file], cwd=work_dir, check=True, capture_output=True, # Capture stdout so it doesn't spam the main run (say in AL) ) except subprocess.CalledProcessError: pass return output_file
[docs] def parse_output(self, output_file: str) -> Dict[str, Any]: results = {"success": False, "energy": None} if not os.path.exists(output_file): return results with open(output_file, "r") as f: try: parsed_data = json.load(f) results.update(parsed_data) except json.JSONDecodeError: pass return results
[docs] def cleanup(self, work_dir: str): """Removes PySCF generated scripts and temp files.""" files_to_delete = [ "run_pyscf.py", "pyscf_results.json", "chkfile.chk", # PySCF default checkpoint file name ] for f in files_to_delete: full_path = os.path.join(work_dir, f) if os.path.exists(full_path): try: os.remove(full_path) except OSError: pass