"""This module provides basic and general information about calculations done using AMS given a calculation directory.This includes information about the engine used (ADF, DFTB, BAND, ...), general information such as timings, files, status of the calculation, etc.This information is used in further analysis programs."""fromtypingimportUnionfrom.importresultResult=result.Resultimportos# noqa: E402importpathlibaspl# noqa: E402from..importslurm# noqa: E402from.importadf,ams,cache,dftb,orca,xtb,crest# noqa: E402
[docs]defget_info(calc_dir:str):try:returnams.get_ams_info(calc_dir)except:# noqapasstry:returnorca.get_info(calc_dir)except:# noqapasstry:returnxtb.get_info(calc_dir)except:# noqapasstry:returncrest.get_info(calc_dir)except:# noqapassres=Result()# if we cannot correctly read the info, we return some generic result object# before that, we check the job status by checking slurmifslurm.workdir_info(os.path.abspath(calc_dir)):res.engine="unknown"state=slurm.workdir_info(os.path.abspath(calc_dir)).statuscodestate_name={"CG":"COMPLETING","CF":"CONFIGURING","PD":"PENDING","R":"RUNNING"}.get(state,"UNKNOWN")res.status.fatal=Falseres.status.name=state_nameres.status.code=stateres.status.reasons=[]else:res.engine="unknown"res.status.fatal=Trueres.status.name="UNKNOWN"res.status.code="U"res.status.reasons=[]# give a little more specific information about the errorifnotos.path.exists(calc_dir):res.status.reasons.append(f"Could not find folder {calc_dir}")elifnotos.path.isdir(calc_dir):res.status.reasons.append(f"Path {calc_dir} is not a directory")else:res.status.reasons.append(f"Could not read calculation in {calc_dir}")returnres
[docs]defread(calc_dir:Union[str,pl.Path])->Result:"""Master function for reading data from calculations. It reads general information as well as engine-specific information. Args: calc_dir: path pointing to the working directory for the desired calculation Returns: dictionary containing information about the calculation """calc_dir=str(calc_dir)ifisinstance(calc_dir,pl.Path)elsecalc_dirret=Result()ret.update(get_info(calc_dir))ifret.engine=="adf":try:ret.adf=adf.get_calc_settings(ret)except:# noqaret.adf=Nonetry:ret.properties=adf.get_properties(ret)except:# noqaret.properties=Nonetry:ret.level=adf.get_level_of_theory(ret)except:# noqaret.level=Noneelifret.engine=="dftb":ret.dftb=dftb.get_calc_settings(ret)ret.properties=dftb.get_properties(ret)elifret.engine=="xtb":# ret.xtb = xtb.get_calc_settings(ret)ret.properties=xtb.get_properties(ret)elifret.engine=="orca":try:ret.orca=orca.get_calc_settings(ret)except:# noqaret.orca=Nonetry:ret.properties=orca.get_properties(ret)except:# noqaret.properties=None# unload cached KFReaders associated with this calc_dirto_delete=[keyforkeyincache._cacheifkey.startswith(os.path.abspath(calc_dir))][cache.unload(key)forkeyinto_delete]returnret
[docs]defquick_status(calc_dir:Union[str,pl.Path])->Result:""" Quickly check the status of a calculation. Args: calc_dir: the directory of the calculation to check. Returns: :Dictionary containing information about the calculation status: - **fatal (bool)** – `True` if calculation cannot be read correctly, `False` otherwise - **reasons (list[str])** – list of reasons to explain the status, they can be errors, warnings, etc. - **name (str)** – calculation status written as a string, one of ("SUCCESS", "RUNNING", "UNKNOWN", "SUCCESS(W)", "FAILED"). If the job is being managed by slurm it can also take values of ("COMPLETING", "CONFIGURING", "PENDING"). - **code (str)** – calculation status written as one or two characters, one of ("S", "R", "U", "W" "F") If the job is being managed by slurm it can also take values of ("CG", "CF", "PD"). """status=Result()status.name='UNKNOWN'status.reasons=[]status.fatal=Truestatus.code='U'forenginein[ams,orca,crest,xtb]:try:status=engine.get_calculation_status(calc_dir)ifstatus.name!='UNKNOWN':returnstatusexceptException:pass# otherwise we check if the job is being managed by slurmifnotslurm.workdir_info(calc_dir):returnstatus# get the statuscode from the workdirstate=slurm.workdir_info(calc_dir).statuscodestate_name={'CG':'COMPLETING','CF':'CONFIGURING','PD':'PENDING','R':'RUNNING'}.get(state,'UNKNOWN')status.fatal=Falsestatus.name=state_namestatus.code=statestatus.reasons=[]returnstatus