bpipe
Welcome to Bpipe
Bpipe为运行大型生物信息学作业提供了一个平台,这些作业由一系列处理阶段组成,称为“管道”。
Bpipe已经发表在《生物信息学》杂志上!
Bpipe官网
Bpipe脚本的一些特性:
-
运行任务的简单定义——Bpipe几乎按原样运行shell命令——不需要编程。
-
任务的事务管理——失败的命令会清除输出,保存日志文件,并干净地终止管道。不会为失控的工作流抓狂。
-
管道阶段的自动连接——Bpipe以一种系统的方式管理每个阶段的输入和输出文件名,因此您不需要考虑它。删除或添加新阶段“只是工作”,不会破坏数据流。
-
容易重新启动作业——当作业失败时,从失败点干净地重新启动。
-
简单的并行性——Bpipe使将作业分割成许多块,并在集群上或本地机器上并行地运行它们变得非常简单
-
自动跟踪——Bpipe记录了执行了哪些命令以及它们的输入和输出。
-
与集群资源管理器集成——如果您使用Torque PBS、Oracle网格引擎或平台LSF,那么Bpipe将使您的工作变得更轻松,因为它允许纯Bpipe脚本在集群上运行,而不需要改变在本地运行它们的方式。
-
通知通过电子邮件,即时消息,消息队列系统- Bpipe可以发送警报,告诉你什么时候你的管道完成,甚至每一个阶段完成。
用法简介
Bpipe实现两个功能:
-
一种用于定义管道阶段并将它们链接在一起以生成管道的小语言
-
用于运行和管理您定义的管道的实用程序
Bpipe不会替换您在管道中运行的命令,而是帮助您更好地运行它们——更安全、更可靠、更方便
pipe语言是用于声明如何运行管道阶段的最小语法。Bpipe实际上是一种基于Groovy的特定于域的语言,Groovy是从Java继承语法的脚本语言。所有Bpipe脚本都是有效的Groovy脚本,大多数Java语法都在Bpipe脚本中工作。但是,使用Bpipe并不需要知道Java或Groovy。
要让Bpipe运行管道,需要为管道的每个部分(每个阶段)指定一个名称。在Bpipe中,管道阶段的命名是这样的:
stage_one = {
exec "shell command to execute stage one"
}
stage_two = {
exec "shell command to execute stage two"
}
Bpipe.run {
stage_one + stage_two
}
Bpipe命令行实用程序
Bpipe附带了一个工具来运行和管理您的脚本,这个工具名为Bpipe,bpipe命令最基本的用途是运行管道。为此,您只需将管道定义保存在一个文件中,然后运行管道:
bpipe run your_pipeline_file
bpipe命令行工具还可以执行对管理管道有用的其他功能:
要重新运行上次在本地目录中运行的管道,请执行以下操作:
bpipe retry
查看一个管道不实际执行时会做什么:
bpipe test your_pipeline_file
要查看作业在本地目录中运行的历史记录:
bpipe history
查看您当前运行的bpipe作业:
bpipe jobs
生信分析实例:Bpipe Example
源代码托管Github
Bpipe语法
变量
Bpipe支持Bpipe脚本中的变量。在Bpipe中有两种变量:
-
隐式变量——Bpipe为您定义的变量
-
显式变量——定义自己的变量
隐式变量
隐式变量是自动提供给Bpipe管道阶段的特殊变量。两个重要的隐式变量是:
-
input—定义作为管道阶段输入的文件的名称
-
output—定义从管道阶段输出的文件的名称
-
分支——当管道运行并行分支时,当前分支的名称在$branch变量中可用。
-
线程——一个特殊的变量,它使Bpipe自动估计并为一个命令分配适当数量的线程
-
内存——一个特殊的变量,它接受bpipe中分配的内存值的值。配置,如果被引用,还会触发Bpipe,根据为管道设置的资源限制(例如:使用Bpipe run -m)来控制它引用的命令
输入和输出变量是Bpipe如何自动地将任务连接在一起形成管道的。一个阶段的默认输入是前一个阶段的输出。通常,您应该始终尝试使用这些变量,而不是将文件名硬编码到命令中。使用这些变量可以确保您的任务是可重用的,并且可以连接在一起形成灵活的管道。
输入和输出变量的扩展语法
Bpipe提供了一种特殊的语法,可以方便地引用具有特定文件扩展名的输入和输出。有关更多信息,请参见ExtensionSyntax。
Multiple Inputs
不同的任务有不同数量的输入和输出,所以当一个具有多个输出的阶段连接到一个只有一个输入的阶段时会发生什么?Bpipe的目标是无论您将什么阶段连接在一起,都要努力使事情正常运行。要做到这一点:
-
变量input1始终是一个单一的文件名,任务可以从中读取输入。如果前一阶段有多个输出,则input1变量是这些输出中的第一个。此输出被视为“主”或“默认”输出。默认情况下,变量$input也计算input1的值。
-
如果一个任务想接受多个输入,那么它可以使用input1、input2等变量引用每个输入。
-
如果一个任务有未知数量的输入,它可以将变量输入引用为列表,并使用数组一样的索引来访问元素,例如输入[0]与input1相同,输入[1]对应于input2,等等。您可以使用input .size()引用输入的大小,并使用类似的语法对输入进行迭代
for(i in inputs) { exec "... some command that reads $i ..." }
-
当一个阶段有多个输出时,第一个这样的输出被视为“主”输出,并作为“输入”变量出现在下一个阶段。如果下一阶段只接受一个输入,那么它的输入将是前一阶段的主要输出。
-
使用ExtensionSyntax将过滤输入,使其只包含特定类型的输入。例如,\(inputs.bam 将对所有扩展名为'.bam',\)input1.bam 将在上游阶段找到第一个bam文件输出。
显式变量
显式变量是您自己定义的变量。这些变量是使用类似java(或Groovy)的语法在Bpipe脚本中内联创建的。可以在任务内部或任务外部定义它们,以便在任务之间共享它们。例如,这里定义了两个变量,并在两个任务之间共享:
NUMTHREADS=8
REFERENCE_GENOME="/data/hg19/hg19.fa"
align_reads = {
exec "bwa aln -t $NUMTHREADS $REFERENCE_GENOME $input"
}
call_variants = {
exec "samtools mpileup -uf $REFERENCE_GENOME $input > $output"
}
注意1:重要的是要理解以这种方式定义的变量具有全局作用域,并且可以修改。如果您的管道中有并行的阶段,那么这一点就变得非常重要。因此,对这些变量的修改可能导致竞态条件、死锁和所有通常出现在多线程编程中的问题。出于这个原因,强烈建议您将此类变量视为常量,并将其赋值一次,然后在脚本的其余部分中将其引用为只读变量。
注意2:显式变量可以在您自己的管道阶段中分配。但是在当前的Bpipe中,它们被分配给全局环境。因此,即使您可以在管道阶段内分配一个变量,它也不是该管道阶段的私有变量。如果您希望一个变量对管道阶段是私有的,请在它前面加上“def”。如果你想和其他管道阶段共享同一个分支(这也将限制在一个线程),你可以用“分支”前缀。
align_reads = {
num_threads=8 // bad idea, this is a global variable!
def thread_num=8 // good idea, this is private
branch.thread_num = 8 // good idea if you want the variable to be visible
// to other stages in the same branch
exec "bwa aln -t $num_threads $REFERENCE_GENOME $input"
}
显示变量值
大多数情况下,使用变量的方法是在使用exec语句运行的shell命令中引用它们。这些语句使用单引号、双引号或三引号定义命令。每种引号对变量展开的处理略有不同:
双引号会导致变量在传递到shell之前被展开。如果输入是"myfile "txt”声明:
exec "echo $input"
结果
echo myfile.txt
因为shell在“myfile”周围看不到引号。如果您的文件名包含空格或shell特殊处理的其他字符,则此操作将失败。要处理这个问题,可以在文件名周围嵌入单引号:
exec "echo '$input'"
单引号使变量无需展开即可传递到shell。因此
exec 'echo $input'
结果:
echo $input
三重引号很有用,因为它们接受嵌入的换行。这允许您跨多行格式化长命令,而无需费力地转义换行。三引号以与单引号相同的方式转义变量,但是它们允许您在传递到shell的命令中嵌入引号。因此,解决上述空格问题的另一种方法是将语句写成:
exec """
echo "$input"
"""
直接引用变量
在任务内部,可以使用类似java(实际上是Groovy)的语法引用变量。在这个例子中,Java代码用于检查输入是否已经存在:
mytask = {
// Groovy / Java code!
if(new File(input).exists()) {
println("File $input already exists!")
}
}
您通常不需要在Bpipe脚本中使用这种语法,但是如果您需要它来处理复杂或高级的场景,那么它是可用的。
区别于Bash变量语法
Bpipe的变量语法基本上与Bash和Perl等语言中的相同语法兼容。这非常方便,因为这意味着您可以直接从命令行复制和粘贴命令到Bpipe脚本中,即使它们使用环境变量
但是Bpipe变量语法和Bash变量语法之间有一些小的区别:
-
Bpipe总是希望\(符号后面跟着一个变量名。因此,Bash中使用\)进行其他操作的操作需要转义$,这样Bpipe就不会解释它。例如:
exec "for i in $(ls **.bam); do samtools index $i; done"
在本例中,$后面加上左括号是非法的,因为Bpipe将尝试将其解释为一个变量。我们可以用反斜杠来解决这个问题:
exec "for i in \$(ls **.bam); do samtools index $i; done"
Bpipe处理 . 作为查询属性的特殊字符,而Bash仅用它分隔变量名。因此,如果您希望编写\(foo.txt来拥有一个带有的文件.txt'附加到变量foo的值后,需要使用大括号:\){foo}.txt。
环境变量
如果引用一个没有定义的变量,Bpipe将其计算为它自己的名称,前面加上\(符号。也就是说,在exec命令中,如果未定义,“\)USER”将计算为“$USER”。这使得变量在命令中作为环境变量“传递”。例如:
exec """
echo $USER
"""
即使用户没有被定义为Bpipe变量,这也将打印用户环境变量的值。注意,Bpipe根本不替换这样一个变量的值。执行命令时,bash执行替换。因此,如果使用计算集群或类似的方法运行命令,则必须为在执行命令的节点上运行的作业定义环境变量的值。
并行运行管道任务
生物信息学管道中经常需要同时执行多个任务。有两种主要的情况你想要这样做:
-
你有一组数据。需要同时进行几项独立操作的
-
您的数据由许多单独的示例组成,这些示例可以通过部分或全部管道独立处理
在这两种情况下,您都可以通过并行而不是顺序执行操作来节省大量时间。Bpipe通过一个简单的语法支持这种并行执行,它可以帮助您声明管道的哪些部分可以同时执行,以及应该向它们输入什么。
在同一数据上同时执行多个阶段任务
假设您有一个非常简单的“hello world”管道,如下所示:
run {
hello + world
}
现在假设您想添加第二个“mars”阶段,它将与“world”管道阶段同时执行。你所需要做的就是把所有的阶段一起执行在方括号里,用逗号隔开:
run {
hello + [ world,mars ]
}
注意:如果您熟悉Groovy语法,您将注意到方括号表示法是您在Groovy中定义列表的方式。因此,我们要说的是,如果您给Bpipe一个要处理的阶段列表,它将并行地执行它们。
你也可以并行执行多个阶段:
Bpipe.run {
hello + [ blue + world, red + mars ]
}
在这里,“blue + world”和“red + mars”形成了并行执行的子管道。你可以有更多的阶段,在最后是顺序的:
Bpipe.run {
hello + [ blue + world, red + mars ] + nice_to_see_you
}
注意,在本例中,最后一个阶段nice_to_see_you要等到前面所有并行执行的阶段都完成后才会执行。它将接收来自“blue + world”和“red + mars”阶段的所有输出组合作为输入。
你也可以嵌套并行任务,如果你希望:
Bpipe.run {
hello + [ blue + world, red + [mars,venus] ] + nice_to_see_you
}
在这种情况下,mars和venus阶段将同时执行,但只有在red阶段完成执行之后。
基于染色体的并行化
在生物信息学中,常常可以同时跨多个染色体进行操作。Bpipe使用下面的特殊语法使这一点很容易实现:
Bpipe.run {
chr(1..5) * [ hello ]
}
这将运行“hello”管道阶段的5个并行实例,每个实例接收相同的文件作为输入。每个阶段都将接收一个隐式chr变量,该变量可用于引用该阶段将要处理的染色体。这可以与许多工具一起使用,这些工具接受染色体作为输入来指定要处理的区域。例如,使用samtools:
hello = {
exec """samtools view test.bam $chr | some_other_tool """
}
可以指定多个范围或单个染色体:
Bpipe.run {
chr(1..10, 'X','Y') * [ hello ]
}
这将运行12个并行阶段,将“chr1”传递到“chr10”、“chrX”和“chrY”作为所有不同阶段的chr变量。
注意:Bpipe还提供了$region变量。如果没有声明基因组(请参阅下面),Bpipe将为管道内的语句发出如下形式的区域:chrN:0-0。许多工具认为这意味着包含整个染色体。但是,如果您声明了一个基因组(参见下面),那么Bpipe将省略一个包含整个染色体的区域,该区域具有该染色体的正确范围
替代的基因组
当通过染色体并行化时,参考序列(如染色体)的格式可以根据使用的底层参考基因组而变化。Bpipe的默认配置是使用UCSC样式约定,在引用序列之前包含“chr”作为前缀。要忽略这一点,同时通知Bpipe基因组的其他方面,请在您的管道开始时声明您正在使用的基因组:
genome 'GRCh37'
对于不包含“chr”前缀的Bpipe识别的基因组,Bpipe在计算\(chr和\)region变量时将使用正确的样式
注:Bpipe将尝试从UCSC下载它所识别基因组的染色体大小。
Parallelising over Arbitrary Genomic Regions
Bpipe还支持分割任意一组基因组区域来并行处理它们。当您希望以比单个染色体更细粒度的方式并行化时,这尤其有用(通常是必要的,因为染色体大小非常不均匀)。有两种方法可以分割一组基因组区域:
-
按间隔大小划分为均匀大小的部件(允许部件数量是动态的)
-
分割为特定数量的部件(允许结果间隔大小是动态的)
Bpipe通过两个名为partition和split的命令支持这两种方法。
Defining Regions
如果想要处理整个“基因组”,可以使用基因组命令声明基因组,然后该基因组将作为一组区域可用。然而,如果你想处理基因组的一个子集(例如。一组exome捕获区域),然后你可以加载自定义的BED文件:
my_regions = bed("/some/path/to/a/bed/file.bed")
Partitioning
对分区区域,使用分区命令,然后是一个阶段列表并行结束:
以1mb大小处理所有hg19:
hg19.partition(1000000) * [ stage1 + stage2 ]
处理自定义区域是完全相同的:
my_regions.partition(1000000) * [ stage1 + stage2 ]
Splitting
若要将区域分割为特定数量的部分,请使用split命令:
hg19.split(40) * [ stage1 + stage2 ]
Bpipe将尝试创建40个均匀的部件,但它不会太努力。也就是说,如果您正在使用一组自定义区域,它将尝试平分区域之间的间隔,并且永远不会将它们分成两半,除非有一个无法减少的大于2:1的比例。这样,除非您分割到一个非常细粒度的级别,否则通常可以依赖Bpipe来保存整个外显子和目标区域,以便用于目标捕获定义。
当分裂整个基因组时,Bpipe将尝试从UCSC下载基因和外显子的定义。然后,它将避免在创建的区域中平分外显子或基因的中间部分(再次强调,除非所需的粒度不能达到结果区域大小之间2:1的比例)。
Branch Names
当您分割或分区一组区域时,Bpipe会自动为每个并行路径分配一个分支名。
-
如果该区域是一个完整的chromosome / contig,那么分支名称就是chromosome / contig的名称
-
否则,Bpipe计算区域的sha1哈希值,并将前8个字符指定为分支名
Accessing Regions
要处理的实际区域可以在管道阶段中使用\(region变量访问,或者在需要时使用\)region.bed文件访问。
Merging Results
请参阅merge points操作符,以了解Bpipe为合并并行段的输出提供的特定支持。
Executing Multiple Stages Simultaneously on Different Data
在上面的例子中,每个并行阶段接收相同的输入文件并一起对它们进行操作。然而,有时您真正想要的是通过相同的阶段(或多个阶段)独立处理每个输入文件或输入文件组。Bpipe调用这种输入分割,并为您提供了一种简洁的实现方法。
假设我们有10个输入文件,并希望同时处理所有10个名为input_1.txt的文件input_10.txt。它是这样的:
Bpipe.run {
"input_%.txt" * [ hello + world ] + nice_to_see_you
}
这里需要注意两件事:1。管道从一个包含%字符的输入分割模式开始,该字符显示应该使用文件名的哪一部分将输入文件分割为组1。管道在管道定义中使用**(或乘法)运算符,而不是通常的+
注意,Bpipe仍然要求您在运行管道时在命令行上指定要匹配的文件;不是对文件系统中的文件进行匹配,而是对管道中的文件进行匹配。如果你把它保存在一个叫'helloworld '的文件中。然后你可以用这样的东西来运行这个例子:
bpipe run helloworld.pipe input*.txt
Input Splitting Patterns
Splitting
Bpipe使用一个非常简单的通配符模式语法来指示应该如何将文件分成多个组进行处理。在这些模式中,您只需用充当通配符(匹配任意数量的字符)的百分号替换文件名称中表示文件所属组的部分。共享相同分组部分的文件将一起传递到要处理的并行管道阶段。
用于文件分组的模式匹配是子字符串匹配。因此,您只需要提供足够的输入文件名来惟一标识分组字符的位置。例如,下面的管道相当于上面的管道:
run {
"_%." * [ hello + world ] + nice_to_see_you
}
这意味着Bpipe将在文件名中查找第一个(也是最短的)令牌,该令牌的两侧有一个下划线和一个句点(。在右边。如果您的文件有部分名称不同,但与您希望如何对它们进行分组无关,那么这可能很有用。
注意:与分组操作符模式不匹配的文件将从输入中全部过滤掉。这个特性非常有用,它允许您拥有一个目录,其中包含作为输入提供的所有文件,即使其中一些不是真正的输入文件——Bpipe将根据您指定的模式过滤掉它需要的文件
Ordering
Bpipe在其输入分割模式中支持另一个特殊字符:通配符。这也可以作为通配符匹配,但它不会将输入分成组。相反,它会影响被分割的组中的排序。当Bpipe在输入分割模式中匹配字符时,它首先将文件分割成它们的组(基于%匹配),然后根据匹配*字符的部分对它们进行排序。这有助于确保即使在拆分之后,文件仍然处于合理的顺序。例如,考虑以下输入文件
-
input_1_1.txt
-
input_1_2.txt
-
input_2_2.txt
-
input_2_1.txt
您可以使用一个模式对输入进行拆分和排序:
"input_%_*.txt"
这个模式将分割和排序的文件如下:
Group 1 - input_1_1.txt, input_1_2.txt
Group 2 - input_2_1.txt, input_2_2.txt
请注意,第二组的文件顺序颠倒了,因为Bpipe对它们进行了排序
Explicitly Specifying Parallel Paths
如果您没有从上述机制中获得所需的灵活性,您可以通过指定一个Groovy列表或一个映射来显式地设置分支路径,该映射告诉Bpipe您想要的路径。当您指定映射时,映射中的键被解释为分支名称,映射中的值被解释为作为输入提供给分支的文件或文件列表。
// Create a data structure (Map) that maps branches to files
def branches = [
sample1: ["sample1_2.fastq.gz"],
sample2: ["sample2_2.fastq.gz"],
sample3: ["sample3_2.fastq.gz"]
]
align = {
// keep the sample name as a branch variable
branch.sample = branch.name
...
}
run { branches * [ align ] }
在本例中,align阶段将并行运行三次,并显式地为每个分支指定文件。当然,在通常情况下,静态地指定它们并不能最好地应用这种技术,但是当您想要从文件、数据库或其他源读取信息并从中构造branch =>文件映射时,这种技术就更适用了
Allocating Threads to Commands
有时,您可以提前确切地知道希望与命令一起使用多少线程。在这种情况下,可以在配置中使用procs属性指定它,或者在管道阶段使用Uses子句直接指定它。
然而,在其他时候,您希望更灵活,并允许更动态地分配资源。这意味着,如果有更多的计算能力可用,您就可以利用它,而当可用的计算能力更少时,您的管道可以按比例缩小,以运行可用的计算能力。Bpipe通过特殊的$threads变量提供了一些功能。这个变量可以表现为两种不同的方式:
-
当从bpipe中提供procs配置时。配置文件,$threads变量将接受该值。
-
当配置没有指定procs配置时,Bpipe将根据通过-n标志指定给Bpipe的当前未使用的并发槽为\(threads确定一个合理的值(默认为运行Bpipe的计算机上的内核数量)。一旦赋值,\)threads将映射到procs配置值中指定的任何命令。
align_bwa = {
exec "bwa aln -t $threads ref.fa $input.fq"
}
在这里,Bpipe将为$threads分配一个值,该值将尽力最好地利用总可用并发性。例如,如果您正在使用的计算机上有32个核,并且其中有4个阶段是并行执行的,那么每个阶段应该分配8个核,只要它们几乎同时开始
Limiting Dynamic Concurrency
Bpipe以某种微妙的方式实现动态并发。当命令要求为\(threads提供一个值时,Bpipe需要决定当前可用线程池应该与哪些其他任务共享。如果它只是立即计算这个值,那么尝试使用\)threads的第一个命令将分配所有剩余的并发槽,而其他命令将没有可用的并发槽。
为了避免这种情况,当命令请求\(threads时,Bpipe将暂停当前分支,并等待管道中所有并发执行路径要么正在执行任务,要么也请求了\)threads。然后将线程分配给所有请求者,并公平分配。
通常,上面的过程会导致将线程“公平”分配给竞争的任务,但是您应该知道,对于那些在时间上分散的任务,仍然可能出现“贪婪”行为。出于这个原因,设置Bpipe将给任何一个任务分配多少线程的上限是很有用的。您可以通过在bpip .config中设置max_per_command_threads变量来实现这一点。这将限制可分配的线程总数。
另一种方法是通过procs变量在命令的配置中指定线程分配范围。例如,我们可以通过在bpipe.config中指定:
commands {
bwa {
procs=2..8
}
}
这将允许Bpipe将$threads设置为2到8之间的任何值。
Limitations
在并行运行阶段时,应该始终使用Bpipe指定的输出文件(为您定义为$output变量),而不是硬编码文件名。这是必需的,因为当您自己定义输出文件时,Bpipe会检测文件的创建,并将它们解释为当前正在执行的管道阶段的输出。然而,在多个阶段执行此检测时,可能会将输出分配到错误的管道阶段,甚至是正确管道阶段的错误并行实例。如果您希望“硬编码”从一个阶段(或)输出的文件名
hello = {
produce("hello.txt") {
exec "cp $input $output"
}
}
即使这样也不建议这样做,因为如果不小心的话,您可能最终会覆盖来自多个并行线程的输出文件。通常,只要有可能,就让Bpipe管理文件的名称,并给它一些提示,使它们看起来像您想要的样子。
分支变量
一个常见的需求是在管道的不同部分之间通信信息。通常,这些信息的作用域是管道中特定分支或段的上下文。Bpipe通过使用“分支变量”来支持这一点
Creating Branch Variables
管道的每个分支(包括根)都传递一个名为“branch”的隐式变量。如果将该变量作为值引用,则该变量计算为运行阶段的分支的名称。例如,如果您使用chr命令按染色体进行拆分,则分支的名称就是执行该分支的染色体。如果您已经按文件进行了分割,那么它就是特定于分支的文件的名称(或其惟一部分)。
然而,branch变量也充当您自己属性的容器。因此,您可以使用普通Groovy代码设置它的属性:
hello = {
branch.planet = "mars"
}
Referencing Branch Variables
一旦设置好,分支变量就可以被分支的所有后续阶段(包括任何子分支)直接引用。该值可以作为branch对象上的属性引用,例如'branch.planet',但也可以参考没有分支。前缀。例如,下面的管道打印“hello mars”:
hello = {
branch.planet = "mars"
}
world = {
exec """echo "Hello $planet" """
}
run { hello + world }
用于引用输入和输出变量的扩展语法
Introduction
当您使用\(input和\)output时,您需要从Bpipe获取通用的输入和输出文件名,它将为您提供与它从管道stage name计算的默认值对应的名称。但是,这些扩展并不总是以非常自然的文件扩展名结束,而且可能不是非常健壮,因为没有指定要使用的文件类型。
例如,$input将引用前一个管道阶段的第一个输出——但是,如果该阶段有多个输出,并且改变了它们的顺序,该怎么办?您的管道阶段将得到错误的文件。为了解决这个问题,您可以将文件扩展名添加到您的输入和输出变量:
align_reads = {
exec "bowtie –S reference $input.fastq | samtools view -bSu - > $output.bam"
}
这里,我们指定了这个管道阶段需要一个文件扩展名为“的输入”。并将输出一个扩展名为“.bam”的文件。第一种方法将导致Bpipe返回到以前的管道阶段,以.fastq结尾的文件作为输入。第二步将确保此阶段的输出文件以“”结尾。bam”文件扩展名。使用这些文件扩展名是可选的,但是它使您的管道更加健壮。
Multiple Inputs
当管道阶段接收到各种类型的多个输入时,您可以使用带有扩展名语法的$input变量来过滤出只包含您感兴趣的文件扩展名的变量。
例如,传递所有以“.bam”'结尾的输入到“merge_bam”命令:
merge_bams = {
exec "merge_bams.sh $inputs.bam"
}
Limitations
目前扩展语法只能过滤单个文件扩展名。因此,您不能要求$input.fastq.gz—这将导致一个错误。对于这些情况,您可以考虑使用from语句来匹配正确的输入:
align_reads = {
from("fastq.gz") {
exec "bowtie –S reference $input.gz | samtools view -bSu - > $output.bam"
}
}
在这里,我们可以确保只匹配以“.fastq”结尾的文件。在我们的领结指挥。
bpipe语句
exec语句
- exec语句以托管方式使用bash shell运行作为参数指定的命令。该命令使用字符串指定,字符串可以是双引号、单引号或三引号。即使使用单引号括起来,变量也会被计算和展开。双引号中的单引号传递给底层shell,因此可以用来传递可能包含空格的值。
- 所有通过exec执行的命令都会自动添加到运行的命令历史记录中
- 如果命令失败或被中断(通过Ctrl-C或kill),管道将自动终止。运行exec命令的阶段指定的任何输出都将被标记为dirty,并移动到本地bpipe垃圾文件夹。
例子
exec "echo 'Hello World'"
exec """
samtools mpileup -uf genome.fa $input | bcftools view -bvcg - > $output
"""
exec """
samtools mpileup
-u
-f genome.fa
$input
|
bcftools view
-b
-v
-c
-g - > $output
"""
cleanup语句
cleanup语句导致Bpipe删除与给定模式匹配的文件,除非需要生成过期的输出,否则在重新执行Bpipe时不会重新创建这些文件。此行为与将相同的文件传递给bpipe cleanup命令相同
例子
清理产生的中间BAM文件
cleanup_bams = {
cleanup "*.dedupe.bam", "*.realign.bam"
}
config语句
config语句允许从管道脚本内部配置Bpipe。请注意,在读取此文件之前,Bpipe已经对配置的某些方面进行了操作,因此不能修改每个配置属性
例子
配置为大数据和小数据使用不同的内存
large_data=true
config {
executor="torque"
memory=large_data ? "24g" : "12g"
}
debug语句
在管道流中的某个点打开Groovy控制台,手动检查变量和管道状态。
例子
hello = {
exec """
echo hello
"""
debug()
}
run {
hello
}
about语句
about语句为管道声明文档,只有title属性,放在任意管道语句的上方
例子:
about title: "Exome Variant Calling Pipeline"
run { align_bwa + picard_dedupe + gatk_call_variants }
doc语句
doc语句将文档添加到管道阶段。它只在管道阶段的声明中有效。doc语句有两种形式
- 一种是简短的形式,允许您给出管道阶段的简单一行描述
- 另一种是更长的形式,允许您指定多个属性。
有效的文档属性是:
title Brief one line description of the pipeline stage
desc Longer description of a pipeline stage
author Name or email address of the author of the pipeline stage
constraints Any warnings or constraints about using the pipeline stage
例子
为管道阶段添加标题
align_with_bwa = {
doc "Align FastQ files using BWA"
}
添加管道阶段的完整文档
align_with_bwa = {
doc title: "Align FastQ files using BWA",
desc: """Performs alignment using BWA on Illumina FASTQ
input files, producing output BAM files. The BAM
file is not indexed, so you may need to follow this
stage with an "index_bam" stage.""",
constraints: "Only works with Illumina 1.9+ format.",
author: "bioinformaticist@bpipe.org"
}
check语句
check语句提供了一种方便的方法来实现对管道输出或进度的验证,并在验证失败时实现替代操作,执行check子句并处理其中的任何exec或其他语句。如果其中一个失败,则执行else子句。
语法
1. check {
< statements to validate results >
}
2. check(<check name>) {
< statements to validate results >
}
3. check {
< statements to validate results >
} otherwise {
<statements to execute on failure >
}
4. check(<check name>) {
< statements to validate results >
} otherwise {
<statements to execute on failure >
}
check的一个方便用法是与成功、失败和发送命令结合使用
例子
检查输出文件的长度是否为非零,如果不是,则使整个管道失败
check {
exec "[ -s $output ]"
} otherwise {
fail "The output file had zero length"
}
检查输出文件的长度是否为非零,如果不是,则仅终止此分支
check {
exec "[ -s $output ]"
} otherwise {
succeed "The output file had zero length"
}
检查输出文件的长度是否为非零,如果不是,则通过电子邮件通知
check {
exec "[ -s $output ]"
} otherwise {
send "Output file $output had zero size" to gmail
}
fail语句
导致管道的当前分支显式终止,并显示故障状态和提供的消息。在最简单的形式中,短消息作为字符串提供。较长的表单允许作为成功的结果生成通知或报告。
例子
导致管道的显式故障
fail "Sample $branch.name has no variants - processing cannot continue"
succeed语句
导致管道的当前分支(或整个管道,如果在根分支中执行)终止,状态为成功,但不产生任何输出。在最简单的形式中,短消息作为字符串提供。较长的表单允许作为成功的结果生成通知或报告。
例子
成功终止分支
succeed "Sample $branch.name has no variants"
send语句
- 通过指定的通信通道发送指定的内容。send的目的是作为管道流的一部分显式地发送内容,比如小报告和状态消息。
- send命令可以发生在执行其他处理的管道阶段中,也可以单独作为专用管道阶段的一部分。
- 内容可以用三种不同的方式指定。第一个选项简单地指定一个直接用作消息的文本字符串。注意,文本字符串必须出现在大括号内。它将在发送之前被惰性地评估。html选项允许以编程方式创建html内容。闭包的主体(即在花括号内)被传递给Groovy MarkupBuilder。这可以用来创建形成HTML电子邮件主体的HTML。
例子
通过Gmail发送消息,包括主题行
send text {"Hello there, this is the message body"} to channel: gmail, subject: "This is an email from Bpipe"
发送一个HTML电子邮件到Gmail
send html {
body {
h1("This Email is from Bpipe")
table {
tr { th("Inputs") }
inputs.each { i -> tr { td(i) } }
}
} to gmail
使用Gmail发送基于模板的消息,并将第一个输出附加为文件
send report("report-template.html") to channel: gmail, file: output1.txt
发送JSON消息
send json(
sample: sample,
sex: "Male"
batch: batch,
run_id: analysis_id
) to analysis_finished_queue
File语句
为给定值创建Java文件对象的方便函数。这在功能上几乎等同于简单地编写“new File(value)”,但是在默认情况下,它还将给定的路径转换为正常的、规范化的表单,而默认构造函数不会这样做,因此File(".").name等值会产生预期的结果。Bpipe不检查文件是否存在或是否为有效路径
例子
将当前工作目录的完整路径传递给需要知道它的命令。* *
hello = {
exec """
mycommand -d ${file(".").absolutePath} -i $input.bam -o $output.bam
"""
}
run { hello }
Filter语句
Filter是一个方便的别名,用于在保持相同的文件扩展名但在文件名中添加新标记的情况下,从输入的名称推断输出的名称。例如,如果有一个命令从CSV文件foo中删除注释行。csv,您可以通过声明一个名为“nocomments”的过滤器,轻松地声明脚本的一个部分来生成输出foo.nocomments.csv。一般情况下,您将使用filter来保持数据的相同格式,但对数据执行一些操作。
filter自动导出的输出将继承generate语句所隐含的所有行为。
您还可以将整个管道阶段声明为过滤器,方法是在阶段之前以@Filter(
)的形式添加过滤器注释。
例子
filter("nocomments") {
exec """
grep -v '^#' $input > $output
"""
}
Transform语句
Transform是一个方便的别名,用于通过修改文件扩展名从输入的名称推断输出的名称。例如,如果您有一个命令将一个名为foo.csv的CSV文件转换为XML文件,那么您可以使用名为“XML”的转换轻松地声明脚本的一个部分来输出foo.xml。
由transform自动导出的输出将继承generate语句所隐含的所有行为。
自0.9.8.4版本以来,transform提供了一个扩展表单,允许您做的不仅仅是替换文件扩展名。本表格由两部分组成,包括:
transform(<input file pattern>) to(<output file pattern>) { ... }
例子
从CSV文件中删除注释行
transform("xml") {
exec """
csv2xml $input > $output
"""
}
在gzip压缩的FASTQ文件上运行FastQC
fastqc = {
transform('.fastq.gz') to('_fastqc.zip') {
exec "fastqc -o . --noextract $inputs"
}
forward input
}
使用通配符模式对两个文件进行Gunzip
transform('*.fastq.gz') to('.fastq') {
exec """
gunzip -cf $input1.fastq.gz > $output1.fastq
gunzip -cf $input2.fastq.gz > $output2.fastq
"""
}
from语句
from语句将输入重新组合为与下面块的给定模式匹配的最新输出文件。当任务需要比前一阶段更早在管道中生成的输入时,或者在输入与Bpipe假定的缺省值不匹配的其他类似情况下,这是非常有用的。
通常,from会嵌入到产品、转换或过滤器块中,但这不是必需的。在这种情况下,from可以直接连接到相同的块,方法是在转换之前使用“from”语句直接连接或过滤。
from接受的模式是使用表示通配符的类全局表达式。没有通配符的模式被视为文件扩展名,例如“csv”被视为“”。,但只会匹配第一个(最近)csv文件。相反,直接使用*. CSV将导致从最后一个阶段输出CSV文件的所有CSV文件匹配第一个参数。后一种形式对于通过不同的并行阶段收集相同类型输出的所有文件特别有用。
当作为列表提供时,from将积累具有不同扩展名的多个文件。当多个文件匹配一个扩展名时,在给定的列表中每次出现该扩展名时,都会顺序使用它们
例子
使用最新的CSV文件生成XML文件
create_excel = {
transform("xml") {
from("csv") {
exec "csv2xml $input > $output"
}
}
}
使用两个文本和CSV文件生成一个XML文件
// Here we are assuming that some previous stage is supplying
// two text files (.txt) and some stage (possibly the same, not necessarily)
// is supplying a CSV file (.csv).
create_excel = {
from("txt","txt","csv") {
exec "some_command $input1 $input2 $input3 > $output.xml" // input1 and input2 will be .txt, input3 will be .csv
}
}
匹配最后阶段生成XML文件的所有CSV文件
from("*.csv") transform("xml") {
exec "csv2xml $inputs.csv > $output"
}
glob函数
返回文件系统中与指定通配符模式匹配的所有文件的列表。该模式使用与shell通配符语法相同的格式。
如果希望将一组文件匹配为管道阶段的输入,而无法使用普通的Bpipe输入变量来实现,那么glob函数非常有用。例如,在需要匹配一组复杂文件的情况下,或者从不同的管道分支中提取的文件,这些分支之间没有相互提供输入。可以在from语句中使用对glob的调用,将匹配的文件提供给输入变量,以便在exec和管道阶段的其他语句中引用它们。
注意:通常,如果可以,最好直接使用通配符模式。这样的表单向后搜索前一阶段的输出,而不是直接在文件系统上搜索。这比仅仅扫描文件系统以查找匹配模式的文件要健壮得多。
例子
运行一个命令,将本地目录中的所有CSV文件作为输入
process_csv = {
from(glob("**.csv")) {
exec "convert_to_xml.py $inputs > $output"
}
}
在本例中,$input变量包含与本地目录中的模式**.csv匹配的所有文件,包括管道的原始输入和中间输出。
grep语句
grep语句是一个内部便利函数,它逐行处理与给定正则表达式匹配的每一行的输入文件。
在第一种形式中,对输入文件中匹配的每一行执行主体,并定义一个隐式变量行。主体可以使用exec执行常规命令,也可以使用本机Groovy / Java命令来处理数据。隐式变量out被定义为一个输出流,它可以写入当前输出文件,这使得使用grep来过滤和处理行并将提取的数据写入输出文件非常方便。
在第二种形式中,grep的工作原理与命令行grep非常相似,输入和输出文件都取自输入和输出变量。在本例中,输入中的所有匹配行都被写入输出
例子
从文件中删除包含INDEL的行
grep(".*") {
if(line.indexOf("INDEL") < 0)
out << line
}
从输入文件创建只包含INDELS的输出文件
grep("INDEL")
using语句
使用指令使变量作为管道构造的一部分在管道阶段内定义。它只在Bpipe run或segment子句中有效。使用说明可以将参数或配置属性传递给管道阶段,以允许它们在不同管道中以不同的方式工作。
例子
hello = {
exec "sleep $time"
exec """echo "hello $name" """
}
run {
hello.using(time: 10, name: "world") + hello.using(time:5, name:"mars")
}
Segment语句
定义可以由多个管道阶段组成的管道的可重用段。然后,段本身的行为就像普通的管道阶段一样。当您希望在管道中多次甚至在单个管道中多次使用一组常见的重复发生的管道阶段序列时,此语句非常有用
例子
hello = {
exec "echo hello"
}
world = {
exec "echo world"
}
hello_world = segment {
hello + world
}
Bpipe.run {
hello_world
}
Preserve语句
使块内语句生成的输出被标记为保留,因此不会被bpipe cleanup命令自动清除。
preserve("*.vcf") {
exec """
java -Xmx8g -jar GenomeAnalysisTK.jar -T UnifiedGenotyper
-R $REF
-I $input.bam
-nt 4
--dbsnp $DBSNP
-dcov 1600
-l INFO
-A AlleleBalance -A Coverage -A FisherStrand
-glm BOTH
-metrics $output.metrics
-o $output.vcf
"""
}
Var语句
定义一个具有默认值的变量,可以使用Using构造覆盖该变量,或者在命令行上传递一个值
例子
向地球问好
hello = {
var WORLD : "world"
doc "Run hello with to $WORLD"
exec """
echo hello $WORLD
"""
}
run { hello }
请注意,下面的脚本与上面的示例相同,除了“run”部分
hello = {
var WORLD : "world"
doc "Run hello with to $WORLD"
exec """
echo hello $WORLD
"""
}
run { hello.using(WORLD: "mars") }
uses语句
uses语句声明所包含的块将使用方括号中声明的资源。资源以表单类型:integer指定,其中预定义的类型是“threads”、“MB”或“GB”。后两者指的是记忆。只需为资源指定任意名称,就可以使用自定义资源类型。
一旦声明了资源,则假定正文中出现的任何exec语句都需要这些资源,如果并发使用的资源超过命令行或配置(bpip .config)中指定的最大值所允许的数量,则exec语句将阻塞。
此语句的目的是帮助您控制并发性,以实现更好的利用率,并防止服务器资源的过度使用,特别是当管道的不同部分具有不同的资源需求时。有些阶段可能能够并行运行许多实例而不超载服务器,而其他阶段可能只能并行运行少量实例而不超载系统。您可以通过在管道的关键部分周围添加use块来解决这些问题,从而在整个管道中获得一致的高利用率
例子
使用4个线程运行bwa,确保每次使用不超过16GB、12个线程和3个临时文件
run_bwa = {
uses(threads:4,GB:4,tempfiles:3) {
exec "bwa aln -t 4 ref.fa $input.fq"
}
}
“tempfiles”是一个自定义资源(bwa实际上并不创建临时文件,我们这样做只是为了举例说明)。
管道将在以下情况下执行
bpipe run pipeline.groovy -n 12 -m 16384 -l tempfiles=3 test.fq
Requires语句
指定此管道阶段运行必须提供的参数或变量。通过在命令行上传递一个值(—param选项),或者直接在管道脚本中定义变量,可以为变量提供一个Using构造。如果这些机制之一没有定义变量,Bpipe将向用户输出一条错误消息,包括require语句定义的消息。
例子
这个管道将打印一个错误,因为没有在任何地方定义WOLRD
hello = {
requires WORLD : "Please specify which planet to say hello to"
doc "Run hello with to $WORLD"
exec """
echo hello $WORLD
"""
}
run { hello }
请注意,下面的脚本与上面的示例相同,除了“run”部分。
hello = {
requires WORLD : "Please specify which planet to say hello to"
doc "Run hello with to $WORLD"
exec """
echo hello $WORLD
"""
}
run { hello.using(WORLD: "mars") }
使用直接定义的变量向mars问好注意,下面的脚本与上面的示例相同,除了“run”部分。
hello = {
requires WORLD : "Please specify which planet to say hello to"
doc "Run hello with to $WORLD"
exec """
echo hello $WORLD
"""
}
WORLD="mars"
run { hello }
执行内联R代码
通过将嵌入的R代码传递给Rscript实用程序来执行它。在传递脚本之前,以\(开头的与已知Bpipe变量匹配的令牌被计算为Bpipe变量。其他此类令牌未经修改即可传递。这样就可以直接在R代码中引用Bpipe变量,比如\)input和$output。
注意:在Bpipe / Groovy名称空间中定义的任何变量都将被计算,包括管道阶段、传递给脚本的参数以及其他参数。因此,重要的是要理解这可能会导致对R代码中变量的意外求值。该特性旨在以一种简单的方式内联小R脚本,例如,快速创建一些结果的图表。较大的R程序应该通过将它们保存为文件并使用Rscript直接运行来执行。\
注意:默认情况下,Bpipe使用在路径中找到的R可执行文件(实际上是Rscript可执行文件)。如果希望设置自定义R可执行文件,可以通过添加bpipe来实现。配置文件,其中包含如下条目:
R {
executable = "/usr/local/R/3.1.1/bin/Rscript"
}
例子
从选项卡分隔的文件中绘制值
R {"""
values = read.table('$input.tsv');
png('$output.png')
plot(values)
dev.off()
"""}
Produce语句
generate语句声明一个语句块,该语句块将以事务方式执行,以创建给定的输出集。在这个上下文中,“事务性”意味着所有语句要么一起成功,要么一起失败,这样输出要么被完全创建,要么一个也不创建(实际上,可以创建一些输出,但是Bpipe会将这些输出移动到trash文件夹中。虽然不需要使用generate来使用Bpipe,但是使用generate可以显式地显示从特定管道阶段创建的输出,从而增强Bpipe脚本的健壮性和清晰度。这会导致以下行为:
如果封闭块中的语句失败或中断,指定的输出将被“清除”,即。移动到垃圾文件夹
隐式变量“output”将被定义为指定的值,允许它在封闭块中使用。基于附加到输出变量的文件扩展名的派生隐式变量也将解析为输出。
- 除非指定了其他输入,否则指定的输出将成为管道中下一阶段的默认输入。
- 如果指定的输出已经存在,并且比所有输入文件都更新,则不会执行generate块中的可执行语句(例如exec或python)。注意,块本身可能被执行,因为Bpipe可能对它求值,以探测对productionsection中没有声明的输入或输出的任何引用。
注意:在大多数情况下,使用方便的包装器过滤器或转换比直接使用generate更有意义,因为这些语句将根据输入的文件名自动为输出确定合适的文件名。
还可以提供通配符模式作为要生成的输入。在这种情况下,$output变量没有分配值,但是在generate块执行之后,将扫描文件系统,寻找匹配通配符模式的文件,并且在运行命令之前发现的任何不存在的文件都将被视为块的输出。
注意:由于Bpipe假设所有匹配的新文件都是从generate块中输出的,所以在并行块中使用通配符模式应该谨慎对待,因为多个执行路径可能会“看到”彼此的文件。
例子
生成一个输出
produce("foo.txt") {
exec "echo 'Hello World' > $output"
}
产生多个输出
produce("foo.txt", "bar.txt") {
exec "echo Hello > $output1"
exec "echo World > $output2"
}
prefix函数
有些工具不直接要求您提供输出文件,而是要求您提供输出文件的前缀,并在前缀后面附加后缀。例如,samtools sort命令要求您为它指定输出的名称,而不使用“”。bam”后缀。为了便于处理,Bpipe提供了一个“魔法”。前缀“extension”,它允许您引用输出,但将其后缀经过修剪的输出传递给实际命令
例子
sort_reads = {
filter("sorted") {
exec "samtools sort -b test.bam $output.prefix"
}
}
这里我们指的是输出“something. ordered”。砰的一声“但只是传递”什么东西。按实际命令排序。
“prefix”函数实际上作用于Bpipe脚本中的任何字符串(或文本)值。你甚至可以这样写:
BASE_FILENAME="test.bam".prefix
注意:当您使用\(output这样的表达式时。前缀,Bpipe认为这是对\)output中的文件的引用,而不是对名为\(output值的文件的引用,这一点很重要。前缀评估。这意味着,如果您的命令没有实际创建\)output计算值为的文件名,那么Bpipe可能会报告一个错误,因为这正是它所期望的。因此,在将前缀结构与输出变量一起使用时要小心,并且只有在您的命令实际创建一个值为$output afte的文件时才使用它们
Output函数
output函数为命令定义一个显式输出。它类似于使用generate子句,但是可以使用${output(…)}形式与命令定义内联使用。在某些情况下,以这种方式定义输出可能更清晰,因为定义与它的使用是搭配的。然而,在许多情况下,如果使用generate子句非常清楚地显示所创建的输出,则读者会更清楚
例子
使输出转到文件“foo.txt”
hello = {
exec """echo world > ${output("foo.txt")}"""
}
forward语句
转发指令使用显式指定的文件覆盖用于下一个管道阶段输入的默认文件。您可以提供硬编码的文件名,但理想情况下,您将传递基于Bpipe自动创建的输入或输出隐式变量的文件,以便您的管道阶段保持通用
Bpipe使用启发式从管道阶段中选择正确的输出,默认情况下,该输出将作为输入传递到下一个阶段(假设下一个阶段没有指定关于它需要哪种输入的任何约束)。然而,有时候,以下阶段通常不需要管道阶段的输出,或者Bpipe的逻辑选择了错误的输出。在这些情况下,使用您自己的逻辑覆盖默认值以指定哪个输出应该成为默认值是很有用的
例子
返回一个BAM文件作为下一个输入,而不是舞台创建的索引文件
index_bam = {
transform(input.bam+'.bai') {
exec """samtools index $input.bam"""
}
forward input.bam
}
Load语句
将指定文件中的管道阶段、变量和函数导入管道脚本。
从0.9.8.7开始,load语句既可以用于顶层(将整个文件导入全局范围),也可以用于管道阶段。在管道阶段中,load语句将文件中的变量和管道阶段导入到当前分支的分支范围中。这可以允许管道的特定分支重写管道阶段,并允许该分支中的变量具有不同的值和行为。
注意:尽管您可以使用load动态地覆盖分支内各个管道阶段的定义,但目前不支持覆盖段的定义。
例子
包含一个文件“依赖项”。显式地导入管道
load "dependencies.groovy"
run {
hello + world // hello and world are defined in dependencies.groovy
}
引用外部文件中定义的变量
config.groovy:
INCLUDE_REALIGNMENT=true
main pipeline script:
load "config.groovy"
// Use realignment if the INCLUDE_REALIGNMENT was defined
if(INCLUDE_REALIGNMENT)
alignment = segment { align + realign }
else
alignment = align
run {
alignment
}
multi语句
multi语句并行执行多个命令,并等待它们全部完成。如果任何一个命令失败,整个管道阶段就会失败,并报告所有的失败。
通常,您希望使用Bpipe内置的并行化特性并行运行多个命令。然而,有时这可能不符合您想要对管道阶段建模的方式。multi语句让我们在管道阶段中执行小规模并行化。
注意:如果希望将计算得到的命令列表传递给multi,请使用multiExec表单(参见下面的示例)
例子
使用逗号分隔的命令列表
hello = {
multi "echo mars > $output1.txt",
"echo jupiter > $output2.txt",
"echo earth > $output3.txt"
}
计算命令列表
hello = {
// Build a list of commands to execute in parallel
def outputs = (1..3).collect { "out${it}.txt" }
// Compute the commands we are going to execute
int n = 0
def commands =[$it > ${outputs[n++]("mars","jupiter","earth"].collect{"echo)}"}
// Tell Bpipe to produce the outputs from the commands
produce(outputs) {
multiExec commands
}
}
run { hello }
合并点
定义一个阶段,该阶段被标识为前面一组并行阶段的合并点。这与使用+操作符几乎相同,但是它会导致Bpipe以不同的方式命名合并阶段的输出。具体地说,通常情况下,merge阶段将根据默认情况下的第一个输入来命名其输出。然而,这常常导致错误地命名输出,这些输出似乎只来自并行段的第一个并行分支。当使用mergepoint操作符时,Bpipe仍然会从第一个输入派生出输出名称,但是它会从该输入的文件名中删除分支名称,并用“merge”替换它,这样输出就可以清楚地标识为以前输入的合并。
当使用动态分支构造时,不能预先准确预测分支名称时,merge point操作符特别有用。
例子
合并来自三个管道分支的输出
这里的管道有三条分支,分别是foo、bar和baz。如果没有使用>>>操作符,那么最终的输出将以foo.there.world.xml结束。但是,由于应用了merge point操作符,最终的输出以.merge.there.world.xml结束
hello = {
exec """
cp -v $input.txt $output.csv
"""
}
there = {
exec """
cp -v $input.csv $output.tsv
"""
}
world = {
exec """
cat $inputs.tsv > $output.xml
"""
}
run {
hello + ['foo','bar','baz'] * [ there ] >>> world
}
拆分hg19 500种方法并将结果合并在一起
注意,这里我们使用了Bpipe的自动区域分割和magic $region.bed变量。
genome 'hg19'
compute_gc_content = {
exec """gc_content -L $region.bed $input.txt > $output.gc.txt"""
}
calculate_mean = {
exec """
cat $inputs.txt | gngs 'println(graxxia.Stats.mean())' > $output.mean.txt
"""
}
run {
hg19.split(500) [ compute_gc_content ] + calculate_mean
}
chr语句
chr语句根据染色体将执行分割为多个并行路径。对于一般情况,作为输入提供的所有文件都被转发到下面列表中提供的每一组并行阶段。
并行执行的阶段接收一个特殊的隐式变量“chr”,它可以用来引用应该处理的染色体。这通常作为参数传递给能够将操作限制在基因组区域内的工具。
注:Bpipe不做任何按染色体分割输入数据的操作:所有接收阶段都得到整个数据集。因此,为了实现这一点,所执行的工具需要支持基因组子区域上的操作
当在管道的染色体特定并行分支内执行时,将自动创建包含染色体名称的输出文件。这确保了不同的并行分支不会试图写入相同的输出文件。例如,将输出文件命名为“hello”。txt“它将被命名为”hello.chr1。如果它是在一个平行的分支处理染色体1
如果作为输入提供的文件包含作为其文件名一部分的染色体段,则对输入进行筛选,以便只将包含相应染色体名的输入转发到包含该名称的并行段。可以通过添加filterinput: false作为chr的附加参数来禁用此行为。
例子
调用人类DNA序列bam文件上的变体,并行地从每个染色体读取数据
gatk_call_variants = {
exec """
java -Xmx5g -jar GenomeAnalysisTK.jar -T UnifiedGenotyper
-R hg19.fa
-D dbsnp_132.hg19.vcf
-glm BOTH
-I $input.bam
-stand_call_conf 5
-stand_emit_conf 5
-o $output.vcf
-metrics ${output}.metrics
-L $chr
"""
}
}
chr(1..22,'X','Y') * [ gatk_call_variants ]