WDL生信

WDL: 快速编写属于你的分析流程

2020-09-05  本文已影响0人  生信云笔记

前言

  一般生物信息分析流程都包含很多的分析步骤,这些步骤之间的联系也有很多情况。例如,流程的步骤中有不少是依赖上一步的结果,同时也有些步骤之间没有联系可以同时进行,还有的步骤需要满足某种情况才运行,也有的步骤需要汇总很多样本的结果来进行分析,等等这些情况。那么一个好的流程应该要满足没有依赖的步骤可以并行分析,需要上一步结果的步骤会自动等待上一步骤执行完毕并调用其结果,需要汇总很多步骤的结果时能够自动等待所有依赖步骤执行完毕然后汇总他们的结果并调用,以及能够处理一些其他的情况等。

  一个优秀的流程工具应该具备良好的组织性、复用性、支持多种集群架构,较低的上手及查错成本。那么有没有这么好用的流程管理工具呢?答案是肯定的。今天我们就来分享一个非常好用且强大的流程管理工具——WDL。目前WDL就是这样一个具备这种潜力的工具,WDL是Broad Institute开发的“human readable and writable”定义组织任务与工作流的一种语言。Cromwell(an execution engine that can run WDL scripts)是基于java编写的可以很好地用来执行WDL语言的引擎工具。WDL+Cromwell就是一套很好的分析流程解决方案。

WDL介绍

结构

  1. WDL:整体是由一个workflow构成,一般写在一个后缀为“.wdl”的文件里面。
  2. workflow:整体有两个部分构成,一是位于头部的input,该部分定义workflow级别的变量,所有的task都可以调用该部分的变量,如果很多步骤都需要使用的变量最好定义在这个部分方便使用;二是使用“call”关键字调用下面定义的task,这个部分的task顺序不代表执行时的顺序,task的执行顺序有任务之间是否有引用关系来决定,如果任务之间没有联系就会平行执行,如果有一个任务需要用到另一个任务的结果时,可以在写流程的时候指定好,这样就在执行的时候就会有先后顺序。
  3. task:主要包含三个部分,一是位于头部的input,该部分定义的是task级别的变量,也就直接给该task自己使用的变量;二是使用“command”关键字定义的具体命令部分,在这里面可以书写的命令就是Linux命令写的一样命令;三是使用“output”关键字定义的输出部分,这样别的任务就可以调用这样输出结果,WDL也正是通过这个来定义任务间的执行顺序;主要是上面三个部分,还有一些可选部分,如可以通过runtime(使用集群时有效)、parameter_meta、meta等关键字来定义任务的运行配置、参数信息、流程信息等。
  4. variable:定义变量的时候可以在类型关键字后面加一个“?”代表这个变量是可选的,也就是可以不提供值的变量,也可以给变量赋一个默认值,这样没有另外给值时就会使用默认值。由于执行引擎Cromwell是基于java编写的,所以定义的变量是强类型的,也就是需要显示地声明变量的类型,变量类型主要包括以下几种:
    String: 字符串类型,
    Float : 浮点型数字,
    Int: 整型的数字,
    Boolean : 布尔类型,只有true和false两种情况,
    File: 文件类型,
    Array : 数组类型,
    Map: 字典类型,
    Object : 对象类型,这个很少用到。

完整WDL示例

上面介绍完WDL基本构成,大家现在知道一个WDL由哪些组件构成的了,后面就是运行这些组件来拼出自己需要的workflow,下面我给出一个尽量包含更多情况的示例,让大家有一个直观地感受,下面来看一下示例代码:

workflow testwdl {
     Int? thread = 6
     String varwdl
     String prefix
     Array[Int] intarray = {1,2,3,4,5}

     if(thread>5) { 
        call taska {
            input:
            vara = varwdl,
            infile = taskb.outfile,
            prefix = prefix
        } 
     }

     scatter (sample in intarray) { 
          call taskb {
               input:
                    varb = 'testb',
                    thread = thread,
                    prefix = sample
          }
     }
}

task taska {
    String vara
    Array[File] infile
    String prefix

    command {
           cat ${sep=" " infile} >${prefix}_${vara}.txt
    }
}

task taskb {
    String varb
    Int thread
    String prefix

    command {
           echo ${varb} ${thread} >${prefix}.txt
    }

    output {
         File outfile = '${prefix}.txt'
    }
}

上面的WDL描述了一个流程包含taska、taskb两个任务,taskb会打印一个文件里面包含“taskb”和threadb变量的值,taska会合并所有taskb的结果,且taska依赖taskb,也就会先执行taskb任务。同时由于taskb任务被包含在scatter循环结构中会被执行多次,这里intarray长度为5,也就是taskb会并行执行五次。taska需要引用taskb的结果,也就是需要等待所有taskb执行完才会执行,这里还需要注意一点,taska的执行还需要thread变量的值大于5,我这里默认设置的是6,如果不修改则taskb执行完肯定会执行taska,如提供一个小于5的thread值,则即使taskb全部执行完taska也不会执行。

WDL执行

流程写好了,下面就可以执行了,但是在执行之前最好用工具检验一下有没有语法错误(如果你相信自己写的WDL没有问题可以跳过这个步骤),这一步并不怎么耗时,个人觉得还是有必要检测一下免得运行了也是出错。

  1. 验证WDL的有效性
java -jar womtool-51.jar validate test.wdl

如果输出结果是“Success!”,那么恭喜你写的WDL没有语法错误,可以接着运行了。

  1. 生成提供变量值的json文件
#生成json文件
java -jar ~/software/cromwell-51/womtool-51.jar inputs test.wdl >test.json
#查看json文件
cat test.json
{
  "testwdl.varwdl": "String",
  "testwdl.intarray": "Array[Int] (optional, default = [1, 2, 3, 4, 5])",
  "testwdl.prefix": "String",
  "testwdl.thread": "Int? (optional, default = 6)"
}

从上面的代码可以看出,我这里写的WDL需要四个输入,其中有两个是有默认值的变量,对于这两个可以不用提供值,另外两个给予相应的值即可,例如,下面是我提供的名为“test.json”的json文件:

{
  "testwdl.varwdl": "helloworld",
  "testwdl.prefix": "test_wdl"
}

输入的json文件也已备好,最后就可以执行WDL了,具体执行命令如下:

java -jar cromwell-51.jar run test.wdl --inputs test.json

流程执行过程的细节都会被记录在log文件中,如果成功地执行了会在log文件中看到类似[2020-09-05 03:04:34,12] [info] SingleWorkflowRunnerActor workflow finished with status 'Succeeded'.提示语句。

WDL结果

流程执行完毕默认会在运行流程的目录下生成两个目录,cromwell-executions和cromwell-workflow-logs分别是执行步骤的文件夹和log文件夹。下面来看一下结果文件夹目录机构,如上面的WDL流程执行完成后的结果目录结构如下所示:

├── cromwell-executions
│   └── testwdl
│       └── 91fd40bd-7a34-41b3-8540-3c9db7b6e580
│           ├── call-taska
│           │   ├── execution
│           │   ├── inputs
│           │   └── tmp.5fe66a06
│           └── call-taskb
│               ├── shard-0
│               ├── shard-1
│               ├── shard-2
│               ├── shard-3
│               └── shard-4
├── cromwell-workflow-logs

从上面的目录结构可以看出同一个WDL流程即使多次执行最新的结果也不会覆盖之前的结果,甚至在同一个目录下运行不同流程的WDL生成的结果也不会相互干扰,这些都得益于WDL的目录结构包含一层随机字符串目录,如这里的“91fd40bd-7a34-41b3-8540-3c9db7b6e580”,所以大家就放心大胆的运行吧!最终每个task的运行中间文件和结构在相应的execution文件下面。
如这里taska的结果在cromwell-executions/testwdl/91fd40bd-7a34-41b3-8540-3c9db7b6e580/call-taska/execution下面,最终的结果文件为test_wdl_helloworld.txt,内容如下:

testb 6
testb 6
testb 6
testb 6
testb 6

现在是不是决定WDL很强大且容易上手,对于这么好的东西是不是有种相见恨晚的感觉,那还在等什么赶紧用起来吧!对于功能这里仅仅展示了一小部分,更多更强的功能留待大家自己在使用中摸索吧!

最后

  前面介绍了WDL的基本构成和用法展示,这里给大家提供一下官网链接方便想深入学习的同学,WDL官网:https://support.terra.bio/hc/en-us/articles/360037117492-Getting-Started-with-WDL。顺便附上执行引擎Cromwell的下载地址,方便需要的同学下载,下载链接:https://github.com/broadinstitute/cromwell/releases后续再更新如何配置集群的配置文件,让WDL可以在集群上运行,这样就可以充分利用集群的资源提升流程整体的运行速度,节省更多时间。emm,今天就先分享到这里吧。

上一篇下一篇

猜你喜欢

热点阅读