The Workflow Description Language (WDL) is a way to specify data processing workflows with a human-readable and -writeable syntax. WDL makes it straightforward to define analysis tasks, chain them together in workflows, and parallelize their execution. The language makes common patterns simple to express, while also admitting uncommon or complicated behavior; and strives to achieve portability not only across execution platforms, but also different types of users. Whether one is an analyst, a programmer, an operator of a production system, or any other sort of user, WDL should be accessible and understandable.
WDL的官方說(shuō)明文檔: Getting Started With WDL
目前在GATK4的流程中,基本都是以WDL的形式編寫(xiě)的。WDL沒(méi)有太多復(fù)雜的邏輯和語(yǔ)法,入門(mén)簡(jiǎn)單。首先看一個(gè)hello world的例子
workflow myWorkflow {
call myTask
}
task myTask {
command {
echo "hello world"
}
output {
String out = read_string(stdout())
}
}
對(duì)于一個(gè)WDL腳本而言,有以下5個(gè)核心結(jié)構(gòu)
1.workflow: 工作流定義
- task : 工作流包含的任務(wù)定義
- call: 調(diào)用或觸發(fā)工作流里面的 task 執(zhí)行
- command: task在計(jì)算節(jié)點(diǎn)上要執(zhí)行的命令行
- output: task 或 workflow 的輸出定義
-
runtime: task在計(jì)算節(jié)點(diǎn)上的運(yùn)行時(shí)參數(shù),包括 CPU、內(nèi)存、docker 鏡像等
image.png
每個(gè)腳本包含1個(gè)workflow, workflow由多個(gè)task構(gòu)成。 在workflow中,通過(guò)call調(diào)用對(duì)應(yīng)的task。每個(gè)task在workflow代碼塊之外單獨(dú)定義。
task代表任務(wù),讀取輸入文件,執(zhí)行相應(yīng)命令,然后輸出。command中對(duì)應(yīng)的就是執(zhí)行的命令,比如一條具體的gatk的命令,output指定task的輸出值??梢詫?code>task理解為編程語(yǔ)言中的函數(shù),每個(gè)函數(shù)讀取輸入的參數(shù),執(zhí)行代碼,然后返回,command對(duì)應(yīng)執(zhí)行的具體代碼,output對(duì)應(yīng)返回值。
在WDL中,也是可以傳遞參數(shù)的。task和workflow中的寫(xiě)法不同
變量利用
我們要把一個(gè)處理步驟構(gòu)造成一個(gè)task, 就要封裝計(jì)算軟件的命令行,那么命令行的參數(shù)如何傳入呢?輸出文件的名字如何指定呢?這些問(wèn)題在 WDL 中可以通過(guò)變量來(lái)解決。比如 Hello world 例子中的 String out 就是一個(gè)字符串類型的輸入,用于指定輸出文件的名字。WDL 中的變量可以定義在 workflow 中,也可以定義在 task中。在command 和 output 中可以通過(guò)$和{}的方式來(lái)引用變量。
變量的類型主要有以下幾種:
- String
- Int
- Float
- File
- Boolean
- Array[T]
- Map[K, V]
- Pair[X, Y]
- Object
workflow 中的參數(shù)
下面的示意圖中, workflow 有3個(gè)參數(shù),文件類型的my_ref,my_input 和字符串類型的name。傳遞這3個(gè)參數(shù)給task時(shí),直接傳變量名就可以了。

task 中的參數(shù)
下面的示意圖中,task 有3個(gè)輸入的參數(shù),文件類型的ref,in 和字符串類型的id。 在command中,通過(guò)${ref}這種格式訪問(wèn)變量的值。

Task 如何組成Workflow呢
作為流程管理語(yǔ)言,需要對(duì)多個(gè)task統(tǒng)一管理。task之間具有多種關(guān)系
1. 線性輸出關(guān)系:

第一種是最常見(jiàn)的場(chǎng)景,簡(jiǎn)單的線性串聯(lián),多個(gè) task 依次執(zhí)行,前面步驟的輸出作為后面步驟的輸入,最后一個(gè) task 的輸出作為整個(gè) workflow 的輸出。
示例如下:
workflow LinearChain {
File firstInput
call stepA { input: in=firstInput }
call stepB { input: in=stepA.out }
call stepC { input: in=stepB.out }
}
task stepA {
File in
command { programA I=${in} O=outputA.ext }
output { File out = "outputA.ext" }
}
task stepB {
File in
command { programB I=${in} O=outputB.ext }
output { File out = "outputB.ext" }
}
task stepC {
File in
command { programC I=${in} O=outputC.ext }
output { File out = "outputC.ext" }
}
2. 多對(duì)多的依賴關(guān)系
一個(gè)task的輸出作為多個(gè)task的輸入,或者多個(gè)task的輸出作為1個(gè)task的輸入
case1:

workflow MultiOutMultiIn {
File firstInput
call stepA { input: in=firstInput }
call stepB { input: in=stepA.out }
call stepC { input: in1=stepB.out1, in2=stepB.out2 }
}
task stepA {
File in
command { programA I=${in} O=outputA.ext }
output { File out = "outputA.ext" }
}
task stepB {
File in
command { programB I=${in} O1=outputB1.ext O2=outputB2.ext }
output {
File out1 = "outputB1.ext"
File out2 = "outputB2.ext" }
}
task stepC {
File in1
File in2
command { programB I1=${in1} I2=${in2} O=outputC.ext }
output { File out = "outputC.ext" }
}
case2:

示例如下:
workflow BranchAndMerge {
File firstInput
call stepA { input: in=firstInput }
call stepB { input: in=stepA.out }
call stepC { input: in=stepA.out }
call stepD { input: in1=stepC.out, in2=stepB.out }
}
task stepA {
File in
command { programA I=${in} O=outputA.ext }
output { File out = "outputA.ext" }
}
task stepB {
File in
command { programB I=${in} O=outputB.ext }
output { File out = "outputB.ext" }
}
task stepC {
File in
command { programC I=${in} O=outputC.ext }
output { File out = "outputC.ext" }
}
task stepD {
File in1
File in2
command { programD I1=${in1} I2=${in2} O=outputD.ext }
output { File out = "outputD.ext" }
}
3. 平行執(zhí)行關(guān)系(并行計(jì)算)

workflow ScatterGather {
Array[File] inputFiles
scatter (oneFile in inputFiles) {
call stepA { input: in=oneFile }
}
call stepB { input: files=stepA.out }
}
task stepA {
File in
command { programA I=${in} O=outputA.ext }
output { File out = "outputA.ext" }
}
task stepB {
Array[File] files
command { programB I=${files} O=outputB.ext }
output { File out = "outputB.ext" }
}
task和函數(shù)還是有一定的區(qū)別,函數(shù)可以在代碼中多次調(diào)用,但是task多次調(diào)用會(huì)有風(fēng)險(xiǎn)。下面的示意圖中,stepA 運(yùn)行兩次,一次作為stepB的輸入,一次作為stepC的輸入。如果stepA的兩次調(diào)用并行執(zhí)行,當(dāng)執(zhí)行完之后,在傳遞給下一個(gè)task時(shí),由于存在兩個(gè)同名的stepA, stepB和stepC 就會(huì)無(wú)法正確接受參數(shù)。

WDL中提供了解決方案,叫做task alias, 為task起一個(gè)別名,示例如下
workflow taskAlias {
File firstInput
File secondInput
call stepA as firstSample { input: in=firstInput }
call stepA as secondSample { input: in=secondInput }
call stepB { input: in=firstSample.out }
call stepC { input: in=secondSample.out }
}
task stepA {
File in
command { programA I=${in} O=outputA.ext }
output { File out = "outputA.ext" }
}
task stepB {
File in
command { programB I=${in} O=outputB.ext }
output { File out = "outputB.ext" }
}
task stepC {
File in
command { programC I=${in} O=outputC.ext }
output { File out = "outputC.ext" }
}
在WDL腳本中, 理論上每個(gè)task 只可以調(diào)用1次,如果希望多次調(diào)用,必須借助task alias。
輸入?yún)?shù)如何傳入
workflow 的輸入,比如基因樣本的存儲(chǔ)位置、計(jì)算軟件的命令行參數(shù)、計(jì)算節(jié)點(diǎn)的資源配置等,可以通過(guò) json 文件的形式來(lái)指定。使用 wdltools 工具可以根據(jù) WDL 文件來(lái)生成輸入模板:

模板格式如下:

當(dāng)然,如果工作流不是很復(fù)雜,也可以按照上面的格式手寫(xiě) input 文件。下面是一個(gè) GATK 工作流的 input 文件的片段.

實(shí)際例子
使用 GATK 構(gòu)建的Jointcalling
workflow定義




掌握以上幾點(diǎn),就可以理解一個(gè)wdl腳本的整體框架了。在實(shí)際使用中,我們只要能理解整個(gè)workflow的流向,會(huì)使用wdl腳本就可以了。 運(yùn)行wdl腳本,需要兩個(gè)文件
- cromwell.jar
- womtools.jar
最新版的下載鏈接如下:
第一步是得到輸入?yún)?shù)的列表,用法如下
java -jar womtools.jar inputs myWorkflow.wdl > myWorkflow_inputs.json
用json格式存存儲(chǔ),這一步得到的只是一個(gè)模板,需要編輯這個(gè)文件,將對(duì)應(yīng)的參數(shù)替換成實(shí)際的參數(shù) 第二步運(yùn)行腳本,用法如下
java -jar Cromwell.jar run myWorkflow.wdl —inputs myWorkflow_inputs.json
reference:
https://developer.aliyun.com/article/716546
https://cloud.tencent.com/developer/article/1626274
