生信工作流与Snakemake基础概念
生信工作流到底在解决什么问题?
做生信分析的人,谁还没被手工操作折磨过?
你想想看,一个GATK标准流程,从原始FASTQ到最终的VCF,中间要经过比对、排序、去重、BQSR、变异 calling、VQSR……少说十来步。每一大步还得分样本,几十上百个样本串行跑,一周能出结果都算快的。
更头疼的是,某一步挂了就得手动改脚本重跑,日志散落一地。到最后写文章的时候,你甚至记不清中间某一步用了什么参数。老实讲,我在刚入行的时候就吃过这个亏——一个RNA-seq项目跑了两个月,最后发现比对步骤索引版本不对,全部重来。
工作流引擎就是来解决这个局面的。说白了,它帮你管理三个东西:
- 执行顺序:谁先跑,谁后跑,依赖关系清晰
- 错误恢复:某步挂了,修好后从断点继续,不用重跑全部
- 环境可复现:步骤、参数、版本全都固化下来,别人也能重复
Snakemake是谁?为什么选它搭GATK管线?
生信工作流工具其实不少,CWL、WDL、Nextflow、Snakemake每家都有拥趸。我个人习惯用Snakemake搭建GATK管线,原因很简单:
| 对比维度 | Snakemake | CWL / WDL | Nextflow |
|---|---|---|---|
| 语法门槛 | 就是Python,会Python就能写 | YAML/JSON描述式,学习曲线陡 | Groovy / DSL2,有一定门槛 |
| GATK内置集成 | 有官方GATK Best Practices示例,生态成熟 | 需要自己写wrapper | nf-core/GATK管线,但也需要了解DSL2 |
| 调试/断点续跑 | 原生支持,非常灵活 | 需要额外配置 | 支持,但不如Snakemake直观 |
| 资源调度 | 支持SLURM / SGE / LSF / 本地 | 需配合Cromwell | 通过executor支持 |
嗯,还有一个很现实的原因:实验室的师弟师妹们大多数只会Python。让他们去写Groovy?别闹了……Snakemake里面直接写Python逻辑,甚至可以在规则里import pandas做数据处理。这种灵活性,在实际折腾GATK管线时太重要了。
你第一个要理解的:Rule(规则)
Snakemake的核心概念很简单,就一个词——Rule。一条规则描述一个步骤:
- input:需要什么输入文件
- output:产生什么输出文件
- shell / run / script:具体跑什么命令或脚本
举个例子,一个bwa比对规则大概长这样:
rule bwa_mem:
input:
ref = "genome.fa",
r1 = "{sample}_R1.fastq.gz",
r2 = "{sample}_R2.fastq.gz"
output:
"{sample}.sorted.bam"
shell:
"bwa mem {input.ref} {input.r1} {input.r2} "
"| samtools sort -o {output}"
看出来没有?那个{sample}就是通配符。一个规则可以匹配任意样本名,Snakemake会自动解析。
{sample}、{chr}、{run_id} 这种有意义的词,别用 {x}、{a}。不然复杂管线写多了,自己都看不懂。
DAG:Snakemake是怎么知道执行顺序的?
Snakemake不靠脚本里的顺序决定谁先跑。它根据所有规则之间的输入输出关系,自动构建出一个有向无环图(DAG)。
比如规则A输出sample.bam,规则B输入sample.bam,Snakemake就自动推导出A必须要在B之前运行。如果依赖有环——比如A依赖B的输出,B又依赖A的输出——那就报错,工作流无法执行。
下面这张图展示了GATK标准流程中几个核心规则的依赖关系:
看这个DAG结构就明白了:Snakemake会从最上方开始解析,只要某个规则的所有输入都准备好了,它就会被调度执行。出错也只是孤立一个节点,修好后从那个节点继续推。
os.path.abspath 或其内置的 workflow.basedir 机制来规避。这一点在正式部署时真的要注意。
Snakefiles:管线就是一堆规则的集合
Snakefile就是Snakemake的执行脚本。里面可以写多个规则、Python函数、全局配置、甚至条件分支。一个典型的Snakefile骨架是:
configfile: "config.yaml" # 外部参数文件
rule all: # 总是定义最终目标
input: "final_output.vcf"
rule step1:
input: "input.fastq"
output: "intermediate.bam"
shell: "some_tool {input} > {output}"
rule step2:
input: "intermediate.bam"
output: "final_output.vcf"
shell: "gatk HaplotypeCaller -I {input} -O {output}"
rule all 是一个伪规则,告诉Snakemake我的最终目标是什么。Snakemake收到这个指令后,就会自动反向推导出中间需要哪些步骤、哪些输入。
rule all,不然Snakemake默认执行第一个规则,在多文件场景下很容易跑偏。
小结:记住这三个概念就够了
Snakemake学习曲线其实很短。你只要能掌握这三样东西,后面GATK管线搭建基本上就水到渠成:
- Rule(规则)——定义每个分析步骤的输入、输出和命令
- DAG(有向无环图)——Snakemake根据输入输出自动推导依赖关系,决定执行顺序
- Snakefile(管线文件)——把规则集合在一起,配上配置文件和最终目标,就是一条完整的管线
说白了,Snakemake就是把“我要做什么”告诉它(rule all),把“每步怎么做”写成规则(rule),剩下的事情——调度、并行、日志、重试——一律交给它。你只需要写好规则,然后坐等结果就行。