作者:童蒙
審稿:同塵
編輯:amethyst
引言
生信分析離不開(kāi)各種各樣的流程。一個(gè)好的流程可以幫我們快速的完成各種各樣的分析覆履。然而怨酝,如何讓我們的流程有更高的復(fù)用性,可移植性漆魔,穩(wěn)定性坷檩,對(duì)于流程的使用而言却音,也非常的重要。
現(xiàn)狀
對(duì)于如何進(jìn)行生信分析矢炼,相信是八仙過(guò)海系瓢,各顯神通。如果實(shí)現(xiàn)一個(gè)簡(jiǎn)單文件的文件句灌,可能執(zhí)行某條語(yǔ)句或運(yùn)行某個(gè)軟件即可夷陋。如果滿足一套復(fù)雜的要求,可能需要多條語(yǔ)句胰锌,用makefile骗绕,bash,或其他腳本語(yǔ)言串連成一個(gè)模塊即可资昧。如果減少一套分析方案的手動(dòng)執(zhí)行過(guò)程酬土,則需要將多個(gè)模塊串成pipeline或workflow…
workflow搭建就像將各個(gè)零件按設(shè)計(jì)圖紙組裝成機(jī)器一樣,圖紙不同格带,機(jī)器不同撤缴。但是如果各部分零件的規(guī)格和接口都不一樣,圖紙?jiān)俸?jiǎn)單叽唱,也是個(gè)復(fù)雜的工程屈呕,甚至只能一次次調(diào)整,耗時(shí)又耗力棺亭。目前生信分析的模塊就是這樣虎眨,沒(méi)有統(tǒng)一的構(gòu)建標(biāo)準(zhǔn)。
除了對(duì)流程進(jìn)行定義缺乏標(biāo)準(zhǔn)外侦铜,如何調(diào)度和監(jiān)控的任務(wù)专甩,實(shí)現(xiàn)任務(wù)的并發(fā)、資源調(diào)度也是一件讓人抓狂的事情钉稍。WDL是board推出的一套便于human readable and writable的流程編寫(xiě)規(guī)則涤躲,其主要的特點(diǎn)在于更適合于生信人員(而非純IT人員)來(lái)書(shū)寫(xiě)流程。
例子
我們先看一個(gè)hello_world的案例
task hello {
input {
String pattern
File in
}
command {
egrep '${pattern}' '${in}'
}
runtime {
docker: "broadinstitute/my_image"
}
output {
Array[String] matches = read_lines(stdout())
}
}
workflow wf {
call hello
}
具體介紹前贡未,從上面的例子我們可以總結(jié)WDL 的一些特點(diǎn):
(1)分層清晰种樱,即使不了解WDL也能明白每部分的作用;
(2)明確定義輸入和輸出俊卤,方便模塊間引用嫩挤。
WDL組件
WDL核心是兩大部分,task 和 workflow消恍,二者組成結(jié)構(gòu)相似岂昭,具體如下:
1. task
task是對(duì)模塊的定義,把通常用的一些命令組合到一起狠怨,形成一個(gè)復(fù)用程度高的集合约啊。以下部分wdl中task包括的元素:
input
為該task的輸入模塊邑遏。如果該模塊有外部輸入,則是必須提供該部分恰矩。
在input內(nèi)部记盒,主要是進(jìn)行變量的聲明。變量的聲明格式為 Type(外傅?+) name=value ,value可以不存在纪吮,由外來(lái)傳入。
其中Type的類型有String萎胰、Int碾盟、Float、Boolean奥洼、File巷疼、Array晚胡、Pair灵奖、Map,以及自定義的Struct類型估盘。
?表示變量可不用傳入信息瓷患,+只能跟在Aarry后面,表示數(shù)組至少有一個(gè)元素遣妥。
當(dāng)定義為File類型時(shí)擅编,會(huì)自動(dòng)檢查文件是否存在,不存在會(huì)報(bào)錯(cuò)箫踩。
有以下例子:
Int? i # An integer value, i is optional
Float f = 27.3 # A floating point number
Boolean b = true # A boolean true/false
String s = "hello, world" # A string value
File f = "path/to/file" # A file
Array[Int] a1
聲明內(nèi)部也支持各種表達(dá)式的爱态,例如“+-*/”等,這一塊跟所有的編程語(yǔ)言很類似境钟,不再贅述锦担。
input之外的聲明
input的聲明是為了參數(shù)外傳,對(duì)于task里的其他中間變量可以寫(xiě)在input外面慨削。
這一部分是可選洞渔,寫(xiě)到input里面和外面好像效果都是一樣的。
command
具體執(zhí)行的命令缚态,最基本的是shell磁椒,也支持其他語(yǔ)言的嵌套,軟件的運(yùn)行命令等玫芦。shell的所有語(yǔ)法浆熔,基本在這個(gè)代碼塊中都適用。例如hello_world中的
egrep '${pattern}' '${in}'
其中{pattern} 是變量的引用桥帆,也可以用~{pattern}來(lái)引用医增。官方建議用~{pattern}來(lái)引用师郑。
runtime
配置該task的運(yùn)行環(huán)境,一般有docker调窍,memory宝冕,cpu等。這一塊用來(lái)設(shè)置運(yùn)行的環(huán)境邓萨、資源等地梨,需要根據(jù)不同的運(yùn)行平臺(tái)進(jìn)行設(shè)置。也可以是變量缔恳,由外部來(lái)導(dǎo)入宝剖。
output
輸出模塊,如果有輸出歉甚,則一定要申明万细,其他模塊在調(diào)用該模塊的結(jié)果時(shí)可以直接引用,比如調(diào)用例子的結(jié)果方式是:hello.matches
聲明的方式同input中一樣纸泄,也支持表達(dá)式赖钞,例如“+-*/”等,如 ${name}+"txt"
也支持變量的內(nèi)插聘裁,例如${name}.txt”
雪营,當(dāng)輸出類型是File時(shí),建議value值用雙引號(hào)引起來(lái)衡便,這樣在下一個(gè)模塊調(diào)用時(shí)才是絕對(duì)路徑献起。
output中有個(gè)glob,可以glob某個(gè)pattern的文件镣陕,返回一個(gè)array谴餐。在某些情況下會(huì)很有用。
在output中還支持很多函數(shù)呆抑,例如read_int()岂嗓,詳情見(jiàn)3中函數(shù)部分。
meta
可選理肺,例如存放作者和版本信息等摄闸。
parameter_meta
可選,相當(dāng)于-h 里面的信息妹萨∧暾恚可以使用wdl-aid來(lái)生成wdl的文檔,方便分享乎完。
2. workflow
將定義的task有機(jī)組合到一起熏兄,就形成了我們常說(shuō)的流程。流程通常是DAG(有向無(wú)環(huán)圖)的瀑布模式。
一個(gè)wdl里面只能有一個(gè)workflow定義摩桶,否則會(huì)報(bào)錯(cuò)桥状。workflow的組成和task很相似,input硝清,output辅斟,meta等定義方式一致,不再贅述芦拿。需要說(shuō)明的是士飒,workflow的output可以直接引用task的結(jié)果,比如:
output {
File outfile1=task1.result
File outfile2=task2.result
}
workflow與task最大的不同是沒(méi)有command蔗崎,而是有call酵幕,即調(diào)用task任務(wù),同時(shí)為實(shí)現(xiàn)多樣的DAG關(guān)系也存在特殊定義缓苛,比如scatter芳撒,if等,具體說(shuō)明如下未桥。
call
call是對(duì)task的直接調(diào)用笔刹,可以直接使用input的參數(shù),也可以調(diào)用其他task的結(jié)果钢属。正是因?yàn)閏all的順序和輸入輸出的先后依賴關(guān)系徘熔,才構(gòu)成了workflow的主要DAG關(guān)系。示例如下:
call my_task as my_task_alias2 {
input:
threshold=threshold,
file1=task1.output1,
file2=task2.output1
}
my_task是定義好的task名稱淆党,as后面是調(diào)用的時(shí)候的名稱,如果同一個(gè)模塊進(jìn)行多次調(diào)用讶凉,需要給不同的別名染乌,以便來(lái)區(qū)分每次調(diào)用后的輸出。大括號(hào)里面的input懂讯,是將workflow的變量傳參到task里, 在workflow里面變量直接調(diào)用即可荷憋,不需要$和雙引號(hào)。
scatter
一個(gè)流程除了串聯(lián)褐望,還有并發(fā)勒庄,這個(gè)可以用scatter結(jié)合Array來(lái)實(shí)現(xiàn)。這個(gè)特性適用于我們有多個(gè)樣品或多個(gè)文件瘫里,并發(fā)運(yùn)行相同的分析实蔽,從而有效的節(jié)省時(shí)間,讓DAG更簡(jiǎn)潔谨读。示例如下:
scatter (i in integers) {
call task1{input: num=i}
call task2{input: num=task1.output}
}
scatter 和for循環(huán)不同局装,它是一種并發(fā)關(guān)系。在此例中,integers是一個(gè)array铐尚,調(diào)度器會(huì)對(duì)array里面的元素進(jìn)行并發(fā)處理拨脉,而不是一個(gè)個(gè)循環(huán)處理。
if
對(duì)變量進(jìn)行判斷宣增,選擇性運(yùn)行某個(gè)task玫膀。注意這個(gè)語(yǔ)法沒(méi)有else。
if(number!=1) { call task1 {input: num=i} }
其他
import
使用import 可以導(dǎo)入task.wdl 或者sub-workflow.wdl爹脾,被workflow直接調(diào)用匆骗。
import "~/wdl/hello_word.wdl" as hello
sub-workflow
workflow本身可以被另一個(gè)workflow import進(jìn)去,以sub-workflow的形式被調(diào)用誉简,可以很方便地作為一個(gè)整體去復(fù)用碉就。
函數(shù)
wdl提供了許多標(biāo)準(zhǔn)的函數(shù)來(lái)幫助實(shí)現(xiàn)簡(jiǎn)單的讀寫(xiě)功能。常用有:
- stdout():標(biāo)準(zhǔn)輸出流
- stderr():標(biāo)準(zhǔn)錯(cuò)誤流
- read_lines():按行讀取闷串,返回array
其他的見(jiàn)說(shuō)明
定義struct
struct Person {
String name
Int age
File input1
}
聲明:Person a
調(diào)用:a.name
使用
WDL可以用cromwell(java) 或者widdler(python)運(yùn)行瓮钥,在下載cromwell(https://github.com/broadinstitute/cromwell/releases)時(shí),可以同時(shí)下載womtool烹吵。womtool可以根據(jù)WDL內(nèi)需要的的input變量生成一個(gè)json版的輸入文件模板碉熄。
輸入文件
使用womtools 生成
java -jar womtool-48.jar inputs test.wdl
即可生成json文件,根據(jù)提示的File肋拔,Int锈津,Array輸入不同的類型的數(shù)據(jù):
{
"task1.inputfile": "new.txt",
"task1.age": "18",
"task1.word": "Say hello"
"task1.samples": ["jia","yi"],
"task1.info": [{"name":"jia","math":"89"},{"name":"yi","math":"93"}]
}
cromwell簡(jiǎn)單運(yùn)行
java -Dconfig.file=test.config -jar cromwell-48.jar run hello_world.wdl -i input.json -o workflow.json
各種配置具體可以查看cromwell官網(wǎng)(https://cromwell.readthedocs.io/en/develop/)
-Dconfig.file 流程配置文件(可選)
可以設(shè)置一系列配置信息,比如打開(kāi)斷點(diǎn)續(xù)跑功能Call Cache凉蜂。
call-caching {
enabled = true
invalidate-bad-cache-results = true
}
run *.wdl 一種運(yùn)行模式
run模式用于本地測(cè)試一個(gè)獨(dú)立的WDL, 不用配置任何信息琼梆,簡(jiǎn)單粗暴,直接運(yùn)行WDL窿吩。另一種模式是server茎杂,服務(wù)器引擎模式,依賴于環(huán)境配置纫雁。
-i 輸入文件
上面提到的WDL需要的各種參數(shù)形成的json文件煌往。
-o workflow 配置文件
可以配置workflow的一下信息,比如最后的目錄整理轧邪。
{
"final_workflow_outputs_dir": ""~/Result",
"use_relative_output_paths": true,
"final_workflow_log_dir": "~/Log",
"write_to_cache": true,
"read_from_cache": true
}
輸出結(jié)果
輸出分為層級(jí)刽脖,里面包含輸入輸出,運(yùn)行腳本忌愚,日志曲管,等各種信息記錄。
ref
https://github.com/openwdl/wdl/blob/master/versions/1.0/SPEC.md#arrayint-rangeint