"""Functions to run CP2K."""from__future__importannotationsimportloggingimportshleximportsubprocessfromos.pathimportexpandvarsfromtypingimportTYPE_CHECKING,AnyfromcustodianimportCustodianfromcustodian.cp2k.handlersimport(AbortHandler,DivergingScfErrorHandler,FrozenJobErrorHandler,NumericalPrecisionHandler,StdErrHandler,UnconvergedRelaxationErrorHandler,UnconvergedScfErrorHandler,WalltimeHandler,)fromcustodian.cp2k.jobsimportCp2kJobfromcustodian.cp2k.validatorsimportCp2kOutputValidatorfromjobflow.utilsimportValueEnumfromatomate2importSETTINGSifTYPE_CHECKING:fromcollections.abcimportSequencefromcustodian.custodianimportErrorHandler,Validatorfromatomate2.cp2k.schemas.taskimportTaskDocument_DEFAULT_HANDLERS=(StdErrHandler(),UnconvergedScfErrorHandler(),DivergingScfErrorHandler(),FrozenJobErrorHandler(),AbortHandler(),NumericalPrecisionHandler(),UnconvergedRelaxationErrorHandler(),WalltimeHandler(),)_DEFAULT_VALIDATORS=(Cp2kOutputValidator(),)logger=logging.getLogger(__name__)
[docs]classJobType(ValueEnum):""" Type of CP2K job. - ``NORMAL``: Normal custodian :obj:`.Cp2kJob`. """DIRECT="direct"NORMAL="normal"
[docs]defrun_cp2k(job_type:JobType|str=JobType.NORMAL,cp2k_cmd:str=SETTINGS.CP2K_CMD,max_errors:int=SETTINGS.CP2K_CUSTODIAN_MAX_ERRORS,scratch_dir:str=SETTINGS.CUSTODIAN_SCRATCH_DIR,handlers:Sequence[ErrorHandler]=_DEFAULT_HANDLERS,validators:Sequence[Validator]=_DEFAULT_VALIDATORS,cp2k_job_kwargs:dict[str,Any]=None,custodian_kwargs:dict[str,Any]=None,)->None:""" Run CP2K. Supports running CP2K with or without custodian (see :obj:`JobType`). Parameters ---------- job_type : str or .JobType The job type. cp2k_cmd : str The command used to run cp2k. max_errors : int The maximum number of errors allowed by custodian. scratch_dir : str The scratch directory used by custodian. handlers : list of .ErrorHandler The error handlers used by custodian. validators : list of .Validator The validators handlers used by custodian. wall_time : int The maximum wall time. If set, a WallTimeHandler will be added to the list of handlers. cp2k_job_kwargs : dict Keyword arguments that are passed to :obj:`.Cp2kJob`. custodian_kwargs : dict Keyword arguments that are passed to :obj:`.Custodian`. """cp2k_job_kwargs=cp2k_job_kwargsor{}custodian_kwargs=custodian_kwargsor{}cp2k_cmd=expandvars(cp2k_cmd)split_cp2k_cmd=shlex.split(cp2k_cmd)ifjob_type==JobType.DIRECT:logger.info(f"Running command: {cp2k_cmd}")return_code=subprocess.call(cp2k_cmd,shell=True)# noqa: S602logger.info(f"{cp2k_cmd} finished running with returncode: {return_code}")returnifjob_type==JobType.NORMAL:jobs=[Cp2kJob(split_cp2k_cmd,**cp2k_job_kwargs)]else:raiseValueError(f"Unsupported {job_type=}")custodian=Custodian(handlers,jobs,validators=validators,max_errors=max_errors,scratch_dir=scratch_dir,**custodian_kwargs,)logger.info("Running CP2K using custodian.")custodian.run()
[docs]defshould_stop_children(task_document:TaskDocument,handle_unsuccessful:bool|str=SETTINGS.CP2K_HANDLE_UNSUCCESSFUL,)->bool:""" Parse CP2K outputs and decide whether child jobs should continue. Parameters ---------- task_document : .TaskDocument A CP2K task document. handle_unsuccessful : bool or str This is a three-way toggle on what to do if your job looks OK, but is actually unconverged (either electronic or ionic): - `True`: Mark job as completed, but stop children. - `False`: Do nothing, continue with workflow as normal. - `"error"`: Throw an error. Returns ------- bool Whether to stop child jobs. """iftask_document.state=="successful":returnFalseifisinstance(handle_unsuccessful,bool):returnhandle_unsuccessfulifhandle_unsuccessful=="error":raiseRuntimeError("Job was not successful (perhaps your job did not converge within the ""limit of electronic/ionic iterations)!")raiseRuntimeError(f"Unknown option for {handle_unsuccessful=}")