[docs]@attr.sclassCmd(Base):"""``Cmd`` class. Attributes: mpi (string): MPI-launcher command. stdout (string): Standard output. If specified, the standard output is redirected to the file specified by ``stdout`` instead of to screen. path (string): Path to the nanodcal+ and rescu+ binaries. """mpi:str=attr.ib(default="",validator=attr.validators.instance_of(str),)path:list[str]=attr.ib(default=[Path(__file__).parent.parent/"_lib/",Path(__file__).parent.parent/"build/src/rescu_calculators",Path(__file__).parent.parent/"build/src/dcal_calculators",])cmd:str=attr.ib(default=None)stdout=attr.ib(default=None)rescuplus_license:Path|None=attr.ib(default=None)nanodcalplus_license:Path|None=attr.ib(default=None)rescuplus_path:Path|None=attr.ib(default=None)nanodcalplus_path:Path|None=attr.ib(default=None)preffered_software:str=attr.ib(default="nanodcalplus")def_find_licenses(self):# check environmetn variablesif"RESCUPLUS_LICENSE_PATH"inos.environ:self.rescuplus_license=os.environ["RESCUPLUS_LICENSE_PATH"]if"NANODCALPLUS_LICENSE_PATH"inos.environ:self.nanodcalplus_license=os.environ["NANODCALPLUS_LICENSE_PATH"]# check default pathsrs_def_path=Path().home()/".nanoacademic/RESCUPLUS/license.lic"ifself.rescuplus_licenseisNoneandrs_def_path.exists():self.rescuplus_license=rs_def_pathnd_def_path=Path().home()/".nanoacademic/NANODCALPLUS/license.lic"ifself.nanodcalplus_licenseisNoneandnd_def_path.exists():self.nanodcalplus_license=nd_def_pathdef_find_binaries(self):forcodenamein("rescuplus","nanodcalplus"):binname=f"{codename}"# search pathsforpinself.path:cmd=Path(p)/f"{binname}"ifcmd.exists():setattr(self,f"{codename}_path",cmd)# system pathfpath=shutil.which(f"{binname}")iffpathisnotNone:setattr(self,f"{codename}_path",Path(fpath))defset_path(self,path):ifisinstance(path,PosixPath):tmp=str(path).split(":")elifisinstance(path,str):tmp=path.split(":")else:ifnotisinstance(path,list):raiseException(f"Invalid object of type {path.__class__.__name__}, must be a str or PosixPath.")tmp=pathtmp=[Path(p)forpintmp]forpintmp:ifnotp.exists():raiseException(f"Failed to set path, directory {p} does not exist.")self.path=tmp
[docs]defget_cmd(self,cmdname):"""Generates NanoDCAL+ or RESCU+ command for a binary of type ``cmdname``. For instance, if ``cmdname = scf``, then it searches for ``nanodcalplus`` and ``rescuplus`` in the path. Then it wraps it with an mpi-launcher command or script, which gives ``mpiexec -n 4 rescuplus``. """# search, in order, RESCU+ or NanoDCAL+ binary to update pathcodenames={"bsu":["rescuplus"],"2prb":["nanodcalplus"],"trsm":["nanodcalplus"],"default":["nanodcalplus","rescuplus"],}self._find_binaries()self._find_licenses()forcodenameincodenames.get(cmdname,codenames["default"]):binname=f"{codename}"cmd=getattr(self,f"{codename}_path",None)ifcmdisNone:continue# check if license is availableifgetattr(self,f"{codename}_license",None)isNone:continue# check if binary is executableifnotos.access(cmd,os.X_OK):raiseException(f"{binname} found but not executable.")self.cmd=codename# check if there is a preffered softwareifself.preffered_software==codename:breakifcmdisNone:ifnotself.rescuplus_licenseandnotself.nanodcalplus_license:raiseException("Failed to find a NanoDCAL+ or RESCU+ license. Please see the installation documentation to set the path or place in default location.")ifnotself.rescuplus_pathandnotself.nanodcalplus_path:raiseException("Failed to find NanoDCAL+ or RESCU+ binary. Please set the path.")# create launch command and return binnameifself.stdoutisNone:deffunction(file):returnsubprocess.run(f"{self.mpi}{cmd} -i {file}".split())else:f=open(self.stdout,"a")deffunction(file):returnsubprocess.run(f"{self.mpi}{cmd} -i {file}".split(),stdout=f,stderr=subprocess.STDOUT,)returnfunction,binname