如何跳过古代的中间规则?

问题描述

如果它们的输出文件已经存在,我想跳过中间规则。

例如,如果要在此基本Snakefile中运行第二条规则,我想跳过第二条规则:

rule third:
    input:
        "b","c"
    output: "d"
    shell: "touch {output}"

rule second:
    input: ancient("b")
    output: "c"
    shell: "touch {output}"

rule first:
    input: "a"
    output: "b"
    shell: "touch {output}"

触摸a后,该管道可以正常工作。

当我再次触摸a时,我希望第二条规则将被跳过,因为输入为 标记ancient。 这不会发生,而是while管道再次运行。

在第三条规则中标记c而不是在第二条规则中标记b也是无效的。

更新:使用该建议,我更新了Snakefile,使其跳过第二条规则(如果该规则之前已执行且未强制执行):

ruleorder: cached_c > second

rule third:
    input:
        "b","c"
    output: "d"
    shell: "touch {output}"

rule second:
    input: "b"
    output:
        c = "c"
    shell: '''
    touch {output.c}
    cp {output.c} cache
    '''

rule cached_c:
    input: "cache"
    output: "c"
    shell: "cp {input} {output}"

rule first:
    input: "a"
    output: "b"
    shell: "touch {output}"

解决方法

如果输入发生更改,确实会阻止规则运行,但是,当蛇形做出更改时,不会运行。您可以运行snakemake -nr来查看运行规则的原因,并且在当前情况下您运行规则是因为Input files updated by another job: b。我遇到过类似的情况,但是我认为这是temp和Ancient之间的相互作用,但我没有意识到这是更普遍的。但是,如果您使用touch b而不是a,则规则第二秒将不会运行。 Ancient阻止其运行,因为忽略了输入文件修改时间;德米特里的描述不正确。

虽然缓存可以工作,但它会向磁盘添加另一个文件,在实际示例中可能不太理想。此外,在规则第三只依赖于c的情况下,由于c的修改时间随复制而更新,因此它仍将重新运行。我要去的是一个输入函数,当输出文件已经存在时,它将返回一个空字符串(或dict,如果使用unpack)。这是Ancient的更强版本,仅当不存在时才会生成输出。例如:

import os

rule third:
    input:
        "b","c"
    output: "d"
    shell: "touch {output}"

def second_input(wildcards):
    if os.path.exists("c"):
        return ""
    else:
        return "b"

rule second:
    input: second_input
    output: "c"
    shell: "touch {output}"

rule first:
    input: "a"
    output: "b"
    shell: "touch {output}"

现在触摸a只会使规则第一个和第三个运行,因为a被更新,然后b被更新。

,

为什么要假设第二条规则将被跳过? ancient修饰符的作用与此相反:

要确定是否必须重新创建输出文件,请使用Snakemake 检查是否有任何文件的修改日期(即时间戳) 同一作业的输入文件比输出的时间戳新 文件。可以通过将输入文件标记为来覆盖此行为 古。此类文件的时间戳将被忽略,并始终假定为 比任何输出文件都要早

因此,即使没有任何更改,也不要总是跳过规则,而是始终运行规则。

该规则具有依赖性的事实意味着您希望只要更改输入,就可以重新评估该规则的输出。您可以通过创建一个单独的规则来手动打破此依赖关系,该规则从 cache 获取输入。缓存的版本不必具有依赖关系(因此永远不会重新评估),并且只要确定文件足以被缓存,就可以手动复制文件。

一种替代方法是在每次成功运行之后(或在每次运行之前,如果发现伪像的话)自动将文件复制到缓存目录中:https://snakemake.readthedocs.io/en/stable/snakefiles/rules.html#onstart-onsuccess-and-onerror-handlers

onsuccess:
    # Copy your files here

更新: 我在消息中提供的Snakemake参考中的引用是含糊的,可以通过两种方式来理解。它没有说Snakemake如何处理古代输入的时间戳并将其链接到可能影响此文件的其他规则。

关于缓存,我个人没有接触过Between workflow caching,但这不是我的意思。 Snakemake不知道更改后的源是否会影响缓存的文件,除非它重新评估文件并比较哈希值。如果您希望避免这种情况(并且您可以确定源中的更改不会影响其余的管道),则可以创建两个单独的分支来创建目标。例如,在您的情况下,您需要一个名为c的文件:我建议您为此制定两个独立的规则:第一个以b作为输入,另一个以cached_b作为输入。您需要使用rulesorder来消除这两个规则的歧义,并赋予缓存的版本优先级。如何创建此cached_b的策略取决于您:手动将b复制到cached_b或正在运行的脚本onsuccess

,

这实际上是一个错误,给出的示例应该产生了正确的行为。

可以找到相关问题herefix今天(2020-10-15)合并。