def _one_day(args): if not args: return cwd = os.getcwd() for a in args: img = os.path.basename(a) d = os.path.dirname(a) if d: os.chdir(d) if not os.path.exists(img): continue if common.MOVIE_SUFFIX.search(img): subprocess.check_call(['open', '-a', 'QuickTime Player.app', img]) else: subprocess.check_call(['open', '-a', 'Preview.app', img]) msg = six.raw_input(a + ': ') if not msg: status = False break if os.path.exists(img): if msg == '!': os.remove(img) print(a + ': removed') else: with open('index.txt', 'a') as f: f.write(img + ' ' + msg + '\n') else: print(a + ': does not exist') if d: os.chdir(cwd) try: os.remove('index.txt~') except Exception: pass return
def concatenate(self, jobfolder): """ Updates content of current job-folder with that of another. :param jobfolder: :py:class:`JobFolder` instance, or :py:class:`JobParams` instance with which to update the current job-folder. Update means that jobs and jobparameters will be overwritten with those from the input. Jobs in the input which are not in the current job-folder will be overwritten. If `jobfolder` is a :py:class:`JobFolder` instance, it is possible to use wildcards in order to select those jobs of interests. .. warning: New jobs are always added at the root of the job-folder. Make sure the jobs bear the names you want. """ import six from .jobfolder import JobFolder from .. import is_interactive keys = jobfolder.keys() if is_interactive: if len(keys) == 0: print("Empty input job-folder. Aborting.") return add = [k for k in keys if k in self] if len(add) > 0: print("Adding the following jobfolderionaries:") for key in add: print(key) update = [k for k in keys if k in self] if len(update) > 0: print("Updating the following jobfolderionaries:") for key in update: print(key) a = '' while a != 'n' and a != 'y': a = six.raw_input("Is the above OK? [n/y] ") if a == 'n': print("Aborting.") return rootadd = jobfolder if isinstance(rootadd, JobParams): rootadd = JobFolder() for key in keys: job = rootadd / key rootadd[key] = jobfolder.jobfolder[key] self.jobfolder.root.update(rootadd)
def __setitem__(self, name, jobfolder): """ Modifies/creates item in job-folder. :param str name: Name of item to modify. :param jobfolder: :py:class:`JobFolder pylada.jobs.jobfolder.JobDict` or :py:class:`JobParams` with which to set/modify item. In the latter case, it should point to a single entry in the job-folder. Eg no wildcards. This function provides the ability to extend a job-folder with other jobs. >>> jobparams['newjob'] = jobparams['oldjob'] >>> jobparams['newjob'] = some_job_dictionary In both cases above, the left-hand-side cannot be a wildcard. Similarly, in the first case above, the right hand side should also point to a valid job, not a sequence of jobs: >>> jobparams['newjobs'] = jobparams['*/oldjobs'] raises KeyError >>> jobparams['*/newjobs'] = jobparams['oldjobs'] No Error! creates a job called '*/newjobs' .. warning:: The right-hand-side is *always* deep-copied_. .. _deep-copied:: http://docs.python.org/library/copy.html """ import six from .. import is_interactive from copy import deepcopy if isinstance(jobfolder, JobParams): try: jobfolder = jobfolder.jobfolder[jobfolder.view] except KeyError: raise KeyError("{0} is not an actual folder".format( jobfolder.view)) if name in self.jobfolder and is_interactive: a = '' while a not in ['n', 'y']: a = six.raw_input( "Modifying existing folder parameters {0}.\nIs this OK? [y/n] " .format(name)) if a == 'n': print("Aborting.") return self.jobfolder[name] = deepcopy(jobfolder)
def __delitem__(self, name): """ Deletes items from job-folder. """ import six from .. import is_interactive if is_interactive: print("Deleting the following jobs:") for key in self[name].keys(): print(key) a = '' while a != 'n' and a != 'y': a = six.raw_input('Ok? [y/n] ') if a == 'n': print("Aborting.") return for key in self[name].keys(): del self.jobfolder.root[key]
def __setitem__(self, name, jobfolder): """ Modifies/creates item in job-folder. :param str name: Name of item to modify. :param jobfolder: :py:class:`JobFolder pylada.jobs.jobfolder.JobDict` or :py:class:`JobParams` with which to set/modify item. In the latter case, it should point to a single entry in the job-folder. Eg no wildcards. This function provides the ability to extend a job-folder with other jobs. >>> jobparams['newjob'] = jobparams['oldjob'] >>> jobparams['newjob'] = some_job_dictionary In both cases above, the left-hand-side cannot be a wildcard. Similarly, in the first case above, the right hand side should also point to a valid job, not a sequence of jobs: >>> jobparams['newjobs'] = jobparams['*/oldjobs'] raises KeyError >>> jobparams['*/newjobs'] = jobparams['oldjobs'] No Error! creates a job called '*/newjobs' .. warning:: The right-hand-side is *always* deep-copied_. .. _deep-copied:: http://docs.python.org/library/copy.html """ import six from .. import is_interactive from copy import deepcopy if isinstance(jobfolder, JobParams): try: jobfolder = jobfolder.jobfolder[jobfolder.view] except KeyError: raise KeyError("{0} is not an actual folder".format(jobfolder.view)) if name in self.jobfolder and is_interactive: a = '' while a not in ['n', 'y']: a = six.raw_input( "Modifying existing folder parameters {0}.\nIs this OK? [y/n] ".format(name)) if a == 'n': print("Aborting.") return self.jobfolder[name] = deepcopy(jobfolder)
def qdel(self, arg): """ Cancel jobs which grep for whatever is in arg. For instance, the following cancels all jobs with "anti-ferro" in their name. The name is the last column in qstat. >>> %qdel "anti-ferro" """ import six import pylada from pylada import qdel_exe if not hasattr(pylada, 'ipython_qstat'): raise RuntimeError( "Missing ipython_qstat function: cannot use %qdel") arg = arg.lstrip().rstrip() if '--help' in arg.split() or '-h' in arg.split(): print(self.qdel.__doc__) return if not arg: result = self.qstat(arg) if not result: print('No jobs in queue') return for name in result.fields(-1): print("cancelling %s." % (name)) message = "Are you sure you want to cancel"\ "the jobs listed above? [y/n] " else: message = "Cancel all jobs? [y/n] " key = '' while key not in ['n', 'y']: key = six.raw_input(message) if key == 'n': return result = self.qstat(arg) for i, name in zip(result.fields(0), result.fields(-1)): # xxx use subprocess self.shell.system('{0} {1}'.format(qdel_exe, i))
def copy_folder(self, event): """ Copies a jobfolder somewhere. Emulates bash's ``cp`` command. By default, it only copies one job. However, it can be made to copy a full tree as well, using the ``-r`` directive. When it finds it would overwrite a non-empty jobfolder, it prompts the user interactively, unless the '-f' directive is given. >>> copyfolder thisjob thatjob Copies ``thisjob`` to ``thatjob``, but not the subfolders of ``thisjob``. By default, the jobfolders are deepcopied. This means that the none of the arguments or functionals of the current job are shared by the copied jobs. However, the relation-ships between the current jobs are retained in the destinations. In other words, if jobs 'JobA' and 'JobA/JobB' share the same 'structure' variable object and they are copied to 'JobC' (with '-r'), then two new subfolders are created, 'JobC/JobA' and'JobC/JobA/JobB'. Both of these subfolders will share a reference to the same `structure` object. However their `structure` object is different from that of the original `JobA` and `JobB`. This feature can be turned off with the option `--nodeepcopy` (in which case, `structure` would be shared by all source and destination folders). Furthermore, if '--nodeepcopy' is used, then the functionals are shared between source and destination. """ import six from argparse import ArgumentParser from os.path import join, normpath, relpath from copy import deepcopy from ..interactive import jobfolder as cjf parser = ArgumentParser( prog='%copyfolder', description='Copies a jobfolder from one location to another') parser.add_argument('-f', '--force', action='store_true', dest='force', help='Does not prompt when overwriting a job-folder.') parser.add_argument('-r', '--recursive', action='store_true', dest='recursive', help='Whether to copy subfolders as well.') parser.add_argument('--nodeepcopy', action='store_true', help='Destination folders will share the parameters ' 'from the original folders.') parser.add_argument('source', type=str, metavar='SOURCE', help='Jobfolder to copy') parser.add_argument('destination', type=str, metavar='DESTINATION', help='Destination folder') try: args = parser.parse_args(event.split()) except SystemExit: return None shell = get_ipython() # gets current folder. if 'jobparams' not in shell.user_ns: print('No jobfolder currently loaded.') return jobparams = shell.user_ns['jobparams'] # normalize destination. if args.destination[0] != ['/']: destination = normpath(join(cjf.name, args.destination)) if destination[0] != '/': print('Incorrect destination', destination) return else: destination = normpath(args.destination) # create list of source directories if args.source[0] != ['/']: source = normpath(join(cjf.name, args.source)) if source[0] != '/': print('Incorrect source', source) return else: source = normpath(args.source) if source not in cjf: print('Source', source, 'does not exist') return if destination == source: print('Source and destination are the same') return rootsource = source pairs = [] if cjf[rootsource].is_executable and not cjf[rootsource].is_tagged: pairs = [(source, relpath(destination, rootsource))] if args.recursive: for source in jobparams[rootsource]: if not cjf[source].is_executable: continue if cjf[source].is_tagged: continue pairs.append((source, join(destination, relpath(source, rootsource)))) if len(pairs) == 0: print("Nothing to copy.") return # now performs actual copy root = deepcopy(cjf.root) if not args.nodeepcopy else cjf.root for source, destination in pairs: # gets the jobfolder source. jobsource = root[source] # gets the jobfolder destination. jobdest = cjf for name in destination.split('/'): jobdest = jobdest / name # something already exists here if jobdest.is_executable and not args.force: print('Copying', jobsource.name, 'to', jobdest.name) a = '' while a not in ['n', 'y']: a = six.raw_input( '{0} already exists. Overwrite? [y/n]'.format( jobdest.name)) if a == 'n': print(jobdest.name, 'not overwritten.') continue # now copies folder items. for key, value in jobdest.__dict__.items(): if key not in ['children', 'parent', 'param']: jobdest.__dict__[key] = value jobdest._functional = jobsource._functional jobdest.params = jobsource.params.copy()
def delete_folder(self, event): """ Deletes a job-folder. By default, only the job itself is delete. If there are no sub-folders, then jobfolder itself is also deleted. Suppose we have a jobfolder '/JobA' and '/JobA/JobB' and both contain actual jobs. >>> deletefolder /JobA This would remove the job-parameters from 'JobA' but leave '/JobA/JobB' unscathed. However, >>> deletefolder /JobA/JobB will remove the branch 'JobB' completely, since there are no sub-folders there. It is also possible to remove all folders of a branch recursively: >>> deletefolder -r /JobA This will now remove JobA and all its subfolders. .. warning:: This magic function does not check whether job-folders are 'on' or 'off'. The recursive option should be used with care. """ import six from argparse import ArgumentParser from os.path import join, normpath from ..interactive import jobfolder as cjf parser = ArgumentParser(prog='%deletefolder', description='Deletes a job-folder.') parser.add_argument('-f', '--force', action='store_true', dest='force', help='Does not prompt before deleting folders.') parser.add_argument('-r', '--recursive', action='store_true', dest='recursive', help='Whether to delete subfolders as well.') parser.add_argument('folder', type=str, metavar='JOBFOLDER', help='Jobfolder to delete') try: args = parser.parse_args(event.split()) except SystemExit: return None shell = get_ipython() # normalize folders to delete if args.folder[0] != ['/']: folder = normpath(join(cjf.name, args.folder)) else: folder = normpath(args.folder) if folder not in cjf: print("Folder", folder, "does not exist.") return # deletes jobfolder recursively. if args.recursive: if not args.force: a = '' while a not in ['n', 'y']: a = six.raw_input( "Delete {0} and its subfolders? [y/n]".format( cjf[folder].name)) if a == 'n': print(cjf[folder].name, "not deleted.") return jobfolder = cjf[folder] if jobfolder.parent is None: jobfolder = jobfolder.parent jobfolder._functional = None jobfolder.children = {} jobfolder.params = {} else: del jobfolder.parent[jobfolder.name.split('/')[-2]] # only delete specified jobfolder. else: if not args.force: a = '' while a not in ['n', 'y']: a = six.raw_input("Delete {0}? [y/n]".format(cjf[folder].name)) if a == 'n': print(cjf[folder].name, "not deleted.") return jobfolder = cjf[folder] if len(jobfolder.children) == 0 and jobfolder.parent is not None: del jobfolder.parent[jobfolder.name.split('/')[-2]] else: jobfolder._functional = None jobfolder.params = {}
def copy_folder(self, event): """ Copies a jobfolder somewhere. Emulates bash's ``cp`` command. By default, it only copies one job. However, it can be made to copy a full tree as well, using the ``-r`` directive. When it finds it would overwrite a non-empty jobfolder, it prompts the user interactively, unless the '-f' directive is given. >>> copyfolder thisjob thatjob Copies ``thisjob`` to ``thatjob``, but not the subfolders of ``thisjob``. By default, the jobfolders are deepcopied. This means that the none of the arguments or functionals of the current job are shared by the copied jobs. However, the relation-ships between the current jobs are retained in the destinations. In other words, if jobs 'JobA' and 'JobA/JobB' share the same 'structure' variable object and they are copied to 'JobC' (with '-r'), then two new subfolders are created, 'JobC/JobA' and'JobC/JobA/JobB'. Both of these subfolders will share a reference to the same `structure` object. However their `structure` object is different from that of the original `JobA` and `JobB`. This feature can be turned off with the option `--nodeepcopy` (in which case, `structure` would be shared by all source and destination folders). Furthermore, if '--nodeepcopy' is used, then the functionals are shared between source and destination. """ import six from argparse import ArgumentParser from os.path import join, normpath, relpath from copy import deepcopy from ..interactive import jobfolder as cjf parser = ArgumentParser(prog='%copyfolder', description='Copies a jobfolder from one location to another') parser.add_argument('-f', '--force', action='store_true', dest='force', help='Does not prompt when overwriting a job-folder.') parser.add_argument('-r', '--recursive', action='store_true', dest='recursive', help='Whether to copy subfolders as well.') parser.add_argument('--nodeepcopy', action='store_true', help='Destination folders will share the parameters ' 'from the original folders.') parser.add_argument('source', type=str, metavar='SOURCE', help='Jobfolder to copy') parser.add_argument('destination', type=str, metavar='DESTINATION', help='Destination folder') try: args = parser.parse_args(event.split()) except SystemExit: return None shell = get_ipython() # gets current folder. if 'jobparams' not in shell.user_ns: print('No jobfolder currently loaded.') return jobparams = shell.user_ns['jobparams'] # normalize destination. if args.destination[0] != ['/']: destination = normpath(join(cjf.name, args.destination)) if destination[0] != '/': print('Incorrect destination', destination) return else: destination = normpath(args.destination) # create list of source directories if args.source[0] != ['/']: source = normpath(join(cjf.name, args.source)) if source[0] != '/': print('Incorrect source', source) return else: source = normpath(args.source) if source not in cjf: print('Source', source, 'does not exist') return if destination == source: print('Source and destination are the same') return rootsource = source pairs = [] if cjf[rootsource].is_executable and not cjf[rootsource].is_tagged: pairs = [(source, relpath(destination, rootsource))] if args.recursive: for source in jobparams[rootsource]: if not cjf[source].is_executable: continue if cjf[source].is_tagged: continue pairs.append((source, join(destination, relpath(source, rootsource)))) if len(pairs) == 0: print("Nothing to copy.") return # now performs actual copy root = deepcopy(cjf.root) if not args.nodeepcopy else cjf.root for source, destination in pairs: # gets the jobfolder source. jobsource = root[source] # gets the jobfolder destination. jobdest = cjf for name in destination.split('/'): jobdest = jobdest / name # something already exists here if jobdest.is_executable and not args.force: print('Copying', jobsource.name, 'to', jobdest.name) a = '' while a not in ['n', 'y']: a = six.raw_input('{0} already exists. Overwrite? [y/n]'.format(jobdest.name)) if a == 'n': print(jobdest.name, 'not overwritten.') continue # now copies folder items. for key, value in jobdest.__dict__.items(): if key not in ['children', 'parent', 'param']: jobdest.__dict__[key] = value jobdest._functional = jobsource._functional jobdest.params = jobsource.params.copy()
def delete_folder(self, event): """ Deletes a job-folder. By default, only the job itself is delete. If there are no sub-folders, then jobfolder itself is also deleted. Suppose we have a jobfolder '/JobA' and '/JobA/JobB' and both contain actual jobs. >>> deletefolder /JobA This would remove the job-parameters from 'JobA' but leave '/JobA/JobB' unscathed. However, >>> deletefolder /JobA/JobB will remove the branch 'JobB' completely, since there are no sub-folders there. It is also possible to remove all folders of a branch recursively: >>> deletefolder -r /JobA This will now remove JobA and all its subfolders. .. warning:: This magic function does not check whether job-folders are 'on' or 'off'. The recursive option should be used with care. """ import six from argparse import ArgumentParser from os.path import join, normpath from ..interactive import jobfolder as cjf parser = ArgumentParser(prog='%deletefolder', description='Deletes a job-folder.') parser.add_argument('-f', '--force', action='store_true', dest='force', help='Does not prompt before deleting folders.') parser.add_argument('-r', '--recursive', action='store_true', dest='recursive', help='Whether to delete subfolders as well.') parser.add_argument('folder', type=str, metavar='JOBFOLDER', help='Jobfolder to delete') try: args = parser.parse_args(event.split()) except SystemExit: return None shell = get_ipython() # normalize folders to delete if args.folder[0] != ['/']: folder = normpath(join(cjf.name, args.folder)) else: folder = normpath(args.folder) if folder not in cjf: print("Folder", folder, "does not exist.") return # deletes jobfolder recursively. if args.recursive: if not args.force: a = '' while a not in ['n', 'y']: a = six.raw_input("Delete {0} and its subfolders? [y/n]".format(cjf[folder].name)) if a == 'n': print(cjf[folder].name, "not deleted.") return jobfolder = cjf[folder] if jobfolder.parent is None: jobfolder = jobfolder.parent jobfolder._functional = None jobfolder.children = {} jobfolder.params = {} else: del jobfolder.parent[jobfolder.name.split('/')[-2]] # only delete specified jobfolder. else: if not args.force: a = '' while a not in ['n', 'y']: a = six.raw_input("Delete {0}? [y/n]".format(cjf[folder].name)) if a == 'n': print(cjf[folder].name, "not deleted.") return jobfolder = cjf[folder] if len(jobfolder.children) == 0 and jobfolder.parent is not None: del jobfolder.parent[jobfolder.name.split('/')[-2]] else: jobfolder._functional = None jobfolder.params = {}
def export(self, event): """ Tars files from a calculation. """ import six import argparse import tarfile from os import getcwd from os.path import exists, isfile, extsep, relpath, dirname, join from glob import iglob from ..misc import RelativePath from .. import interactive from . import get_shell shell = get_shell(self) parser = argparse.ArgumentParser(prog='%export', description='Exports input/output files from current job-folder. ' 'Depending on the extension of FILE, this will create ' 'a simple tar file, or a compressed tar file. Using the ' 'option --list, one can also obtain a list of all files ' 'which would go in the tar archive. ' 'Finally, this function only requires the \"collect\" ' 'exists in the usernamespace. It may have been declared ' 'from loading a job-folder using \"explore\", or directly ' 'with \"collect = vasp.MassExtract()\".') group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--list', action="store_true", dest="aslist", help='Do not tar, return a list of all the files.') group.add_argument('filename', metavar='FILE', type=str, default='export.tar.gz', nargs='?', help='Path to the tarfile. Suffixes ".gz" and ".tgz" indicate ' 'gzip compression, whereas ".bz" and ".bz2" indicate bzip ' 'compression. Otherwise, no compression is used.') parser.add_argument('--input', action="store_true", dest="input", help='Include input (INCAR/crystal.d12) files.') parser.add_argument('--dos', action="store_true", dest="dos", help='Include Density of States (DOSCAR) files.') parser.add_argument('--structure', action="store_true", dest="structure", help='Include structure input (POSCAR) files.') parser.add_argument('--charge', action="store_true", dest="charge", help='Include charge (CHGCAR) files.') parser.add_argument('--contcar', action="store_true", dest="contcar", help='Include CONTCAR files.') parser.add_argument('--wavefunctions', action="store_true", dest="wavefunctions", help='Include wavefunctions (WAVECAR/crystal.98) files.') parser.add_argument('--procar', action="store_true", dest="procar", help='Include PROCAR files.') group = parser.add_mutually_exclusive_group(required=False) group.add_argument('--down', action="store_true", dest="down", help='Tar from one directory down.') group.add_argument('--from', type=str, dest="dir", default=None, help='Root directory from which to give filenames. ' 'Defaults to current working directory.') group.add_argument('--with', type=str, dest="others", nargs='*', help='Adds pattern or filename to files to export.' 'Any file in any visited directory matching the given pattern ' 'will be added to the archive. This options can be given more than ' 'once if different file patterns are required.') try: args = parser.parse_args(event.split()) except SystemExit as e: return None collect = shell.user_ns.get('collect', None) rootpath = getattr(collect, 'rootpath', None) if collect is None: print("Could not find 'collect' object in user namespace.") print("Please load a job-dictionary.") return kwargs = args.__dict__.copy() kwargs.pop('filename', None) if rootpath is None: if hasattr(shell.user_ns.get('collect', None), 'rootpath'): rootpath = shell.user_ns.get('collect').rootpath directory = getcwd() if rootpath is None else dirname(rootpath) if args.down: directory = join(directory, '..') elif args.dir is not None: directory = RelativePath(args.dir).path # set of directories visited. directories = set() # set of files to tar allfiles = set() for file in collect.files(**kwargs): allfiles.add(file) directories.add(dirname(file)) # adds files from "with" argument. if hasattr(args.others, "__iter__"): for pattern in args.others: for dir in directories: for sfile in iglob(join(dir, pattern)): if exists(sfile) and isfile(sfile): allfiles.add(sfile) # adds current job folder. if interactive.jobfolder_path is not None: if isfile(interactive.jobfolder_path): allfiles.add(interactive.jobfolder_path) # now tar or list files. if args.aslist: from IPython.utils.text import SList directory = getcwd() return SList([relpath(file, directory) for file in allfiles]) else: # get filename of tarfile. args.filename = relpath(RelativePath(args.filename).path, getcwd()) if exists(args.filename): if not isfile(args.filename): print("{0} exists but is not a file. Aborting.".format(args.filename)) return a = '' while a not in ['n', 'y']: a = six.raw_input("File {0} already exists.\nOverwrite? [y/n] " .format(args.filename)) if a == 'n': print("Aborted.") return # figure out the type of the tarfile. if args.filename.find(extsep) == -1: endname = '' else: endname = args.filename[-args.filename[::-1].find(extsep) - 1:][1:] if endname in ['gz', 'tgz']: tarme = tarfile.open(args.filename, 'w:gz') elif endname in ['bz', 'bz2']: tarme = tarfile.open(args.filename, 'w:bz2') else: tarme = tarfile.open(args.filename, 'w') for file in allfiles: tarme.add(file, arcname=relpath(file, directory)) tarme.close() print("Saved archive to {0}.".format(args.filename))
def savefolders(self, event): """ Saves job-folder to disk. This function can be called in one of three ways: >>> savefolders filename.dict rootfolder In this case, "filename.dict" is a file where to save the jobfolder "rootfolder". The latter must be a python variable, not another filename. The current job-folder becomes "rootfolder", and the current path >>> savefolders filename.dict Saves the current job-folder to "filename.dict". Fails if no current job-folder. >>> savefolders Saves the current job-folder to the current job-folder path. Fails if either are unknown. """ import six from os.path import exists, isfile from ..jobfolder import JobParams, MassExtract as Collect, save from .. import interactive from ..misc import RelativePath from . import get_shell shell = get_shell(self) args = [u for u in event.split()] if "--help" in args or "-h" in args: print(savefolders.__doc__) return if len(args) > 2: print("savefolders takes zero, one, or two arguments.") return if len(args) == 2: from .explore import explore explore(self, args[1]) savefolders(self, args[0]) return if interactive.jobfolder is None: print("No current job-folder.") print("Please load first with %explore.") return jobfolder = interactive.jobfolder.root jobfolder_path = interactive.jobfolder_path if len(args) == 1: jobfolder_path = RelativePath(args[0]).path interactive.jobfolder_path = jobfolder_path if jobfolder_path is None: print("No current job-folder path.\n" "Please specify on input, eg\n" ">saveto this/path/filename") return if exists(jobfolder_path): if not isfile(jobfolder_path): print("{0} is not a file.".format(jobfolder_path)) return a = "y" # testValidProgram: force yes to allow automated testing while a not in ["n", "y"]: a = six.raw_input("File %s already exists.\nOverwrite? [y/n] " % jobfolder_path) if a == "n": print("Aborting.") return save(jobfolder.root, jobfolder_path, overwrite=True, timeout=10) if len(args) == 1: if "collect" not in shell.user_ns: shell.user_ns["collect"] = Collect(dynamic=True, path=jobfolder_path) if "jobparams" not in shell.user_ns: shell.user_ns["jobparams"] = JobParams()
def savefolders(self, event): """ Saves job-folder to disk. This function can be called in one of three ways: >>> savefolders filename.dict rootfolder In this case, "filename.dict" is a file where to save the jobfolder "rootfolder". The latter must be a python variable, not another filename. The current job-folder becomes "rootfolder", and the current path >>> savefolders filename.dict Saves the current job-folder to "filename.dict". Fails if no current job-folder. >>> savefolders Saves the current job-folder to the current job-folder path. Fails if either are unknown. """ import six from os.path import exists, isfile from ..jobfolder import JobParams, MassExtract as Collect, save from .. import interactive from ..misc import RelativePath from . import get_shell shell = get_shell(self) args = [u for u in event.split()] if '--help' in args or '-h' in args: print(savefolders.__doc__) return if len(args) > 2: print("savefolders takes zero, one, or two arguments.") return if len(args) == 2: from .explore import explore explore(self, args[1]) savefolders(self, args[0]) return if interactive.jobfolder is None: print("No current job-folder.") print("Please load first with %explore.") return jobfolder = interactive.jobfolder.root jobfolder_path = interactive.jobfolder_path if len(args) == 1: jobfolder_path = RelativePath(args[0]).path interactive.jobfolder_path = jobfolder_path if jobfolder_path is None: print("No current job-folder path.\n"\ "Please specify on input, eg\n"\ ">saveto this/path/filename") return if exists(jobfolder_path): if not isfile(jobfolder_path): print("{0} is not a file.".format(jobfolder_path)) return a = 'y' # testValidProgram: force yes to allow automated testing while a not in ['n', 'y']: a = six.raw_input("File %s already exists.\nOverwrite? [y/n] " % jobfolder_path) if a == 'n': print("Aborting.") return save(jobfolder.root, jobfolder_path, overwrite=True, timeout=10) if len(args) == 1: if "collect" not in shell.user_ns: shell.user_ns["collect"] = Collect(dynamic=True, path=jobfolder_path) if "jobparams" not in shell.user_ns: shell.user_ns["jobparams"] = JobParams()
def export(self, event): """ Tars files from a calculation. """ import six import argparse import tarfile from os import getcwd from os.path import exists, isfile, extsep, relpath, dirname, join from glob import iglob from ..misc import RelativePath from .. import interactive from . import get_shell shell = get_shell(self) parser = argparse.ArgumentParser( prog='%export', description='Exports input/output files from current job-folder. ' 'Depending on the extension of FILE, this will create ' 'a simple tar file, or a compressed tar file. Using the ' 'option --list, one can also obtain a list of all files ' 'which would go in the tar archive. ' 'Finally, this function only requires the \"collect\" ' 'exists in the usernamespace. It may have been declared ' 'from loading a job-folder using \"explore\", or directly ' 'with \"collect = vasp.MassExtract()\".') group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--list', action="store_true", dest="aslist", help='Do not tar, return a list of all the files.') group.add_argument( 'filename', metavar='FILE', type=str, default='export.tar.gz', nargs='?', help='Path to the tarfile. Suffixes ".gz" and ".tgz" indicate ' 'gzip compression, whereas ".bz" and ".bz2" indicate bzip ' 'compression. Otherwise, no compression is used.') parser.add_argument('--input', action="store_true", dest="input", help='Include input (INCAR/crystal.d12) files.') parser.add_argument('--dos', action="store_true", dest="dos", help='Include Density of States (DOSCAR) files.') parser.add_argument('--structure', action="store_true", dest="structure", help='Include structure input (POSCAR) files.') parser.add_argument('--charge', action="store_true", dest="charge", help='Include charge (CHGCAR) files.') parser.add_argument('--contcar', action="store_true", dest="contcar", help='Include CONTCAR files.') parser.add_argument( '--wavefunctions', action="store_true", dest="wavefunctions", help='Include wavefunctions (WAVECAR/crystal.98) files.') parser.add_argument('--procar', action="store_true", dest="procar", help='Include PROCAR files.') group = parser.add_mutually_exclusive_group(required=False) group.add_argument('--down', action="store_true", dest="down", help='Tar from one directory down.') group.add_argument('--from', type=str, dest="dir", default=None, help='Root directory from which to give filenames. ' 'Defaults to current working directory.') group.add_argument( '--with', type=str, dest="others", nargs='*', help='Adds pattern or filename to files to export.' 'Any file in any visited directory matching the given pattern ' 'will be added to the archive. This options can be given more than ' 'once if different file patterns are required.') try: args = parser.parse_args(event.split()) except SystemExit as e: return None collect = shell.user_ns.get('collect', None) rootpath = getattr(collect, 'rootpath', None) if collect is None: print("Could not find 'collect' object in user namespace.") print("Please load a job-dictionary.") return kwargs = args.__dict__.copy() kwargs.pop('filename', None) if rootpath is None: if hasattr(shell.user_ns.get('collect', None), 'rootpath'): rootpath = shell.user_ns.get('collect').rootpath directory = getcwd() if rootpath is None else dirname(rootpath) if args.down: directory = join(directory, '..') elif args.dir is not None: directory = RelativePath(args.dir).path # set of directories visited. directories = set() # set of files to tar allfiles = set() for file in collect.files(**kwargs): allfiles.add(file) directories.add(dirname(file)) # adds files from "with" argument. if hasattr(args.others, "__iter__"): for pattern in args.others: for dir in directories: for sfile in iglob(join(dir, pattern)): if exists(sfile) and isfile(sfile): allfiles.add(sfile) # adds current job folder. if interactive.jobfolder_path is not None: if isfile(interactive.jobfolder_path): allfiles.add(interactive.jobfolder_path) # now tar or list files. if args.aslist: from IPython.utils.text import SList directory = getcwd() return SList([relpath(file, directory) for file in allfiles]) else: # get filename of tarfile. args.filename = relpath(RelativePath(args.filename).path, getcwd()) if exists(args.filename): if not isfile(args.filename): print("{0} exists but is not a file. Aborting.".format( args.filename)) return a = '' while a not in ['n', 'y']: a = six.raw_input( "File {0} already exists.\nOverwrite? [y/n] ".format( args.filename)) if a == 'n': print("Aborted.") return # figure out the type of the tarfile. if args.filename.find(extsep) == -1: endname = '' else: endname = args.filename[-args.filename[::-1].find(extsep) - 1:][1:] if endname in ['gz', 'tgz']: tarme = tarfile.open(args.filename, 'w:gz') elif endname in ['bz', 'bz2']: tarme = tarfile.open(args.filename, 'w:bz2') else: tarme = tarfile.open(args.filename, 'w') for file in allfiles: tarme.add(file, arcname=relpath(file, directory)) tarme.close() print("Saved archive to {0}.".format(args.filename))
def launch(self, event, jobfolders): """ Launches each jobfolder in single pbs job """ import six import subprocess from copy import deepcopy from os.path import dirname, join, basename, exists from os import remove from ... import pbs_string, default_pbs, qsub_exe, default_comm from .. import get_shell from . import get_walltime, get_queues, get_mppalloc from . import asone_script shell = get_shell(self) pbsargs = deepcopy(dict(default_comm)) pbsargs.update(default_pbs) pbsargs['ppn'] = event.ppn if not get_walltime(shell, event, pbsargs): return if not get_queues(shell, event, pbsargs): return # gets python script to launch in pbs. pyscript = asone_script.__file__ if pyscript[-1] == 'c': pyscript = pyscript[:-1] # creates file names. hasprefix = getattr(event, "prefix", None) def pbspaths(directory, jobname, suffix): """ creates filename paths. """ name = '{0}-{1}{2}'.format(event.prefix, jobname, suffix) if hasprefix \ else '{0}{1}'.format(jobname, suffix) return join(directory, name) # now loop over jobfolders pbsscripts = [] for current, path in jobfolders: # Check number of jobs directory, nbjobs = dirname(path), 0 for name, job in current.root.items(): # avoid jobfolder which are off if job.is_tagged: continue # avoid successful jobs.unless specifically requested if hasattr(job.functional, 'Extract') and not event.force: p = join(directory, name) extract = job.functional.Extract(p) if extract.success: print("Job {0} completed successfully. " \ "It will not be relaunched.".format(name)) continue nbjobs += 1 if path.rfind('.') != -1: name = path[:path.rfind('.')] # now creates script pbsargs['n'] = get_mppalloc(shell, event, False) pbsargs['nnodes'] = (pbsargs['n'] + pbsargs['ppn'] - 1) \ // pbsargs['ppn'] pbsargs['err'] = pbspaths(directory, name, '.err') pbsargs['out'] = pbspaths(directory, name, '.out') pbsargs['name'] = basename(path) pbsargs['directory'] = directory pbsargs['scriptcommand'] \ = "{0} --nbprocs {n} --ppn {ppn} --pools={1} {2}" \ .format(pyscript, event.pools, path, **pbsargs) pbsscripts.append(pbspaths(directory, name, '.script')) # write pbs scripts if exists(pbsscripts[-1]): a = '' while a not in ['n', 'y']: a = six.raw_input("PBS script {0} already exists.\n" "Are you sure this job is not currently running [y/n]? " .format(pbsscripts[-1])) if a == 'n': print("Aborting.") return remove(pbsscripts[-1]) with open(pbsscripts[-1], "w") as file: string = pbs_string(**pbsargs) if hasattr(pbs_string, '__call__') \ else pbs_string.format(**pbsargs) file.write(string) assert exists(pbsscripts[-1]) print("Created pbsscript {0} for job-folder {1}." \ .format(pbsscripts[-1], path)) if event.nolaunch: return # otherwise, launch. for script in pbsscripts: cmdLine = "{0} {1}".format(qsub_exe, script) subprocess.call(cmdLine, shell=True)