3.5。工作经理

工作经理是Plams环境的“指挥官”。 它创建了工作文件夹的结构,管理其内容,并跟踪您运行的所有作业。

每一个例子 JobManager 与工作文件夹相关联。 此文件夹是创建的 JobManager 实例是初始化的,并且该实例管理的所有作业都有工作文件夹中的作业文件夹。 在创建后,您不应该更改作业管理器的工作文件夹。

初始化plams环境时 init() 功能,一个实例 JobManager 是创建和存储的 config.default_jobmanager 此实例与主工作文件夹相关联(参见 启动脚本 有关详细信息)并每次需要与作业管理器进行一些交互时用作默认值。 在正常情况下,您永远不会明确互动 JobManager 实例(手动创建它,调用其任何方法,探索其数据等)。 所有互动都自动处理 run() or other methods.

技术的

通常不需要使用任何其他作业管理员而不是默认的作业管理器。 分裂在多个实例之间的工作 JobManager 可能会导致一些问题(不同的实例不沟通,所以 重新运行预防 不能正常工作)。

但是,可以手动创建另一个实例 JobManager (with a different working folder) and use it for part of your jobs (by passing it as 工作manager keyword argument to run())。 如果您决定这样做,请确保通过所有实例 JobManager 你手动创造了 finish() (as a list).

一个示例应用程序,可以在许多不同的计算机上运行脚本中的作业(例如通过SSH)并单独 JobManager on each of them.

3.5.1。重新运行预防

在某些情况下,例如,当运行许多自动生成的小作业时,可能发生两个或更多作业是相同的 - 它们具有相同的输入文件。 PLAMS具有内置机制来检测这种情况并避免不必要的工作。

run(),就在实际工作执行之前,一个唯一的标识符(调用 哈希)计算工作。 职位管理器存储先前启动作业的所有哈希,并检查您刚刚运行的作业的哈希是否已发生。 如果检测到这样的情况,则跳过执行当前作业的执行,并使用先前作业的结果。 Results from previous job’s folder can be either copied or linked to the current job’s folder, based on link_files key in 以前的 job’s 设置.

笔记

链接使用硬链接完成。 Windows不支持硬链接,因此如果您在Windows结果下运行PLAM,则始终复制。

整个Rerun预防逻辑的关键部分是一个正确的工作 哈希() function. 它是一种占用整个作业实例并产生其哈希的函数。 散列函数需要为不同的作业生成不同的哈希度,并且完全相同的哈希,用于完成完全相同的工作。 由于有关工作准备的技术细节可能会差异很多,因此远远差异很大程度上要出现适用于所有外部二进制文件。 目前实现的方法基于计算输入和/或runScript内容的SHA256散列。 The value of 哈希ing key in job manager’s 设置 can be one of the following: 'input', 'runscript', 'input+runscript' (or None to disable the rerun prevention).

如果您决定实现自己的散列方法,可以通过覆盖来完成 哈希_input() and/or meth:〜scm.plams.core.basejob.singlejob.hash_runscript..

警告

可能发生的是,具有相同输入和runScript文件的两个作业对应于不同的作业(例如,如果它们依赖于使用相对路径提供的某些外部文件)。 有时它甚至是运行相同作业的多个不同副本的所需行为(例如,具有相同起点和随机初始速度的多个MD轨迹)。 If you are experiencing problems (PLAMS refuses to run a job, becasue it was already run in the past), you can disable the rerun prevention with config.default_jobmanager.settings.hashing = None.

哈希被禁用 MultiJob 实例因为它们没有输入和运行件。 当然,多jobs的孩子的单一工作是以正常方式散列的,所以试图运行两次两次的多腹部,不会触发re run预防在多档水平上,而是为每个孩子的工作分别,有效地防止任何一倍的工作。

3.5.2。酸洗

整个PLAM环境的寿命仅限于单个脚本。 That means every PLAMS script you run uses its own independent job manager, working folder and config settings. 这些对象在脚本的开头初始化 init() 命令并在脚本结束时停止存在。 还有所有设置调整(除了通过编辑完成的设置 默认文件)是本地的,它们只影响当前脚本。

结果是, JobManager 当前脚本不了解在过去脚本中运行的任何作业。 但是,通常将先前运行的作业导入到当前脚本并使用其结果或基于它构建一些新作业是非常有用的。 为此,Plams为作业对象提供数据保存。 每次执行工作成功完成(见 跑步工作), the whole job object is saved to a .dill file using Python serialization called pickling. Such a .dill file can be loaded (“unpickled”) in future scripts using load() function:

oldjob = load('/home/user/science/plams_workdir/myjob/myjob.dill')

这个操作带回了旧的 Job 在(差不多)中的实例相同的状态就在执行完成后。

笔记

默认的Python酸洗包 pickle 不足以处理一些常见的普遍普遍的普通对象。 Fortunately, the 莳萝 package provides an excellent replacement for pickle, following the same interface and being able to save and load almost everything. It is strongly recommended to use 莳萝 to ensure proper work of PLAMS data preservation logic. However, if 莳萝 是 not installed for the Python interpreter you’re using to run PLAMS, the regular pickle package will be used instead (which can work if your Job 对象不是太喜欢,但在大多数情况下它可能会失败)。 Please use 莳萝, it’s free, easy to get and awesome.

酸洗机制遵循腌制物体的引用。 这意味着如果您尝试泡制的对象包含对另一个对象的引用(就像a Job 实例有一个参考a Results 实例),也保存了其他对象。 由于未划分后,您的对象中没有“空”引用。 However, every Job Plam中的实例是对作业管理员的引用,反过来有引用所有其他工作,所以酸洗一份作业会有效地意味着酸洗整个环境。 To avoid that, every Job 需要通过删除对“全局”对象的引用以及一些本地属性(例如,对作业文件夹的路径)来准备酸洗。 在加载期间,所有已删除的数据都替换为“正确”值(当前作业管理器,作业文件夹等当前路径等)。

笔记

有一种扩展上述机制的方法。 If your Job object has an attribute with reference to an object you don’t want to save together with the job, you may add this object’s name to job’s _dont_pickle list:

myjob.something = some_big_and_clumsy_object_you_dont_want_to_pickle
myjob._dont_pickle.append('something')

That way big clumsy object will not be stored in the .dill file. After loading such a .dill file the value of myjob.something will simply be None.

_dont_pickle list is an attribute of every Job 实例,最初是一个空列表。 It does not contain names of attributes that are always removed (like 工作manager), it’s meant only for additional ones defined by the user (see Job.__getstate__)

如上所述,酸洗一项工作发生在最后 run(). The decision if a job should be pickled is based on the pickle key in job’s 设置, so it can be adjusted for each job separately. If you wish not to pickle a particular job just set myjob.settings.pickle = False. Of course the global default config.job.pickle can also be used.

如果修改工作或相应的作业 Results instance after it has been pickler, these changes are not going to be reflected in the .dill file, since it was created before the changes happened. To update the state of the .dill file to include such changes you need to repickle the job manually by calling myjob.pickle() after doing your changes.

笔记

并非所有Python对象都可以正确纠错,所以你需要小心你的其他物体 Job (或它 Results)存储引用。

Results 与作业关联的实例与它一起保存。 但是,这些结果不包含作业执行产生的所有文件,而是仅包含对它们的相对路径。 For that reason the .dill file is not enough to fully restore the job object if you want to extract or process the results. 需要作业文件夹中存在的所有其他文件 Results 实例可以看到它们。 因此,如果要将先前运行的作业复制到另一个位置,请务必复制 整体 作业文件夹(包括子目录)。

一个工作加载 load()不是 在当前的工作经理中注册。 这意味着它在当前工作文件夹中没有得到自己的子文件夹,它永远不会被重命名并且没有 清洁作业文件夹 完成了 finish(). 但是,它被添加到散列注册表中,因此它是可见的 重新运行预防.

如果是 MultiJob all the information about children jobs is stored in parent’s .dill file so loading a MultiJob 导致装载所有孩子。 Each child job can have its own .dill file containing information about that particular job only. When pickling, the parent attribute of a job is erased, so loading a child job does not result in loading its parent (and all other children).

3.5.3。重新启动脚本

酸洗和重新运行的预防将组合成一个方便的重启机制。 当您的脚本尝试执行某些“非法”时,提出了异常,脚本由Python解释器终止。 通常它是由脚本中的错误(使用错误的变量,访问列表等的错误元素)引起的。 在这种情况下,人们想纠正脚本并再次运行它。 但是,在发生异常之前,终止脚本中的一些作业可能已经运行并成功完成。 如果它们意味着以先前产生完全相同的结果,则将浪费时间在更正的脚本中再次运行这些作业。 解决方案是在新脚本的开头加载来自旧脚本的所有成功作业,让 重新运行预防 do the rest. But having to go to the old script’s working folder and manually get paths to all .dill files present there would be cumbersome. 幸运的是,人们可以使用 load_all() function which takes a path to the main working folder of some finished PLAMS run and loads all .dill files present there. 因此,当您编辑崩溃的脚本以删除错误时,您只能添加一个 load_all() 在开始时拨打电话。 然后,您运行更正的脚本,没有完成不必要的工作:所有完成的作业都是从上一个运行加载的,当前运行尝试再次运行相同的作业,但是 重新运行预防 检测该文件和副本/将旧作业的文件夹链接到当前的主工作文件夹中。

如果您正在使用plams脚本使用 启动脚本 重新启动甚至更容易。 它可以用两种方式完成:

  1. If you wish to perform the restart run in a fresh, empty working folder, all you need to do is to import the contents of the previous working folder (from the crashed run) using -l flag:

    plams myscript.plms
    [17:28:40] PLAMS working folder: /home/user/plams_workdir
    #[crashed]
    #[correct myscript.plms]
    plams -l plams_workdir myscript.plms
    [17:35:44] PLAMS working folder: /home/user/plams_workdir.002
    

    This is eqivalent to putting load_all('plams_workdir') at the top of myscript.plms and running it with the usual plams myscript.plms.

  2. If you would prefer an in-place restart in the same working folder, you can use -r flag:

    plams myscript.plms
    [17:28:40] PLAMS working folder: /home/user/plams_workdir
    #[crashed]
    #[correct myscript.plms]
    plams -r myscript.plms
    [17:35:44] PLAMS working folder: /home/user/plams_workdir
    

    In this case the launch script will temporarily move all the contents of plams_workdir to plams_workdir.res, import all the jobs from there and start a regular run in now empty plams_workdir.

笔记

请记住,Rerun Prevention在后面检查工作的哈希哈希 prerun() method is executed. 因此,当您尝试运行与先前运行的作业相同的作业时(在同一脚本中或从上一个运行导入)时,它 prerun() 无论如何都执行方法,即使其余部分也是如此 跑步工作 是 skipped.

3.5.4。 API.

班级 JobManager(设置, 路径=无, 文件夹= none)[来源]

负责作业和文件管理的班级。

每个实例都具有以下属性:

  • 文件夹name - 工作文件夹名称。
  • workdir - 工作文件夹的绝对路径。
  • logfile - 日志文件的绝对路径。
  • input - 工作文件夹中输入文件副本的绝对路径。
  • 设置 - 一种 Settings 此工作管理器的实例(见下文)。
  • 工作s - 使用此实例管理的所有作业的列表(按顺序排列) run() calls).
  • names - 用作业名称的字典。对于每个名称,存储整数值,指示已经运行了该基本名的作业数量。
  • 哈希es - 用作作业的哈希表的字典。

小路 argument should be be a path to a directory inside which the main working folder will be created. If None, the directory from where the whole script was executed is used.

文件夹name attribute is initially set to the 文件夹 argument. If such a folder already exists, the suffix .002 是 appended to 文件夹 and the number is increased (.003, .004…) until a non-existsing name is found. If 文件夹None, the name plams_workdir 是 used, followed by the same procedure to find a unique 文件夹name.

设置 attribute is directly set to the value of 设置 参数(与他们被复制的其他类别不同),它应该是一个 Settings 使用以下键的实例:

  • 哈希ing - 选择散列方法(见 重新运行预防)。
  • counter_len - 在名称冲突的情况下,向作业名称附加到作业名称的数量。
  • remove_empty_directories – if True, all empty subdirectories of the working folder are removed on finish().
__init__(设置, 路径=无, 文件夹= none)[来源]

初始化自我。请参阅帮助(类型(self))以获得准确的签名。

load_job(文件名)[来源]

加载以前保存的工作 文件名.

文件名 should be a path to a .dill file in some job folder. A Job instance stored there is loaded and returned. All attributes of this instance removed before pickling are restored. That includes 工作manager, 小路 (the absolute path to the folder containing 文件名 是 used) and default_settings (a list containing only config.job)。

酸洗 for details.

remove_job(工作)[来源]

去掉 工作 来自工作经理。忘记它的哈希。

_register_name(工作)[来源]

注册姓名 工作.

如果已注册具有相同名称的作业, 工作 是 renamed by appending consecutive integers. The number of digits in the appended number is defined by the counter_len value in 设置.

_register(工作)[来源]

注册 工作。注册作业的名称(如果需要重命名)并创建作业文件夹。

_check_hash(工作)[来源]

计算哈希 工作 and, if it is not None, search previously run jobs for the same hash. If such a job is found, return it. Otherwise, return None

_clean()[来源]

Clean all registered jobs according to the save parameter in their 设置. If remove_empty_directoriesTrue, traverse the working directory and delete all empty subdirectories.