Aurora blog

バイオインフォ・バイオテクノロジーにまつわる情報

CWL②:BioContainer / scatter / when

CWLを学ぶ part 2

以前のエントリでCWL (Common Workflow Language) について簡単にまとめたが、マニュアルやgithubを見ていると、いくつか知らない機能があることがわかったので、改めてメモを残しておこうと思う。

auroratummy.hatenablog.com

github.com

BioContainer

CWLとは直接は関係がないが、BioContainerには、多種多様なバイオインフォ系のツールをすぐに実行可能なDocker/Singularityイメージが登録されている。マイナーなツールもかなり見つかるので、まずはここを検索してみることを推奨する。

biocontainers.pro

Scatter

複数のサンプルのFASTQファイルを同じリファレンスゲノムにマッピングする場合など、同一作業を繰り返す場合に使われる。*1

ここでは複数のgzipファイルを一つずつ解凍するワークフローを考える。以下のyamlを書くと変数gzに複数ファイルを配列として格納することができる。

# scatter_example.yaml
gz:
  - class: File
    location: test_data_16s_light/ERR3668533_15_L001_R1_001.fastq.gz
  - class: File
    location: test_data_16s_light/ERR3668533_15_L001_R2_001.fastq.gz
  - class: File
    location: test_data_16s_light/ERR3668534_15_L001_R1_001.fastq.gz
  - class: File
    location: test_data_16s_light/ERR3668534_15_L001_R2_001.fastq.gz

stepsの中でscatterを使うことで、複数の入力に対して同一のステップを繰り返し実行することができる。以下の例では、配列gzに含まれる各ファイルに対して、ステップgunzipを繰り返している。この場合、ステップgunzipの出力も配列となるため、このワークフローの出力gunzippedの型にはファイルの配列 (File[]) を指定している。requirementsにScatterFeatureRequirementをつけないとエラーとなるので注意。

# scatter_example.cwl
cwlVersion: v1.2
class: Workflow
doc: scatter test

requirements:
    ScatterFeatureRequirement: {} # これが必要

inputs:
    gz:
        label: gzipped files
        type: File[]

steps:
    gunzip:
        run: components/gunzip.cwl
        scatter: gz # ここ
        in:
            gz: gz
        out: [gunzipped]

outputs:
    gunzipped:
        type: File[]
        outputSource: gunzip/gunzipped

when

CWL version 1.2から追加された機能。これを使うことでif/else的な条件分岐が可能となる。

入力seq_typese(single-end)とpe(paired-end)の場合でデータ処理のパイプラインを変える場合を想定する。この場合はstepにwhenを以下のように挟むことで条件分岐を実現することができる。この場合注意すべきは、ステップpipeline_sepipeline_peseq_typeを入力として受け取る必要がない場合でも、whenを使う場合にはinputにseq_typeを入れなければエラーが出る仕様になっているので注意。*2

# when_example.cwl
cwlVersion: v1.2
class: Workflow
doc: scatter test

requirements:
    InlineJavascriptRequirement: {}
    MultipleInputFeatureRequirement: {}

inputs:
    input_file_dir:
        label: input directory
        type: Directory
    seq_type:
        label: sequencing type ("pe" or "se")
        default: "se"
        type: string

steps:
    pipeline_se:
        in:
            seq_type: seq_type
            input_file_dir: input_file_dir
        when: $(inputs.seq_type == "se")
        run: components/pipeline_se.cwl
        out: [out]

    pipeline_pe:
        in:
            seq_type: seq_type
            input_file_dir: input_file_dir
        when: $(inputs.seq_type == "pe")
        run: components/pipeline_pe.cwl
        out: [out]

outputs:
  result:
    type: File
    outputSource:
      - pipeline_se/out
      - pipeline_pe/out
    pickValue: first_non_null 

ファイルを一箇所にまとめる

ワークフローでたくさんのファイルが出力される場合は、それを特定の名前のディレクトリに集約できるとありがたい。その方法が紹介されているページ*3があったのでメモ。以下のようにExpressionToolで実現できる。

cwlVersion: v1.0
class: ExpressionTool
requirements:
  InlineJavascriptRequirement: {} 

inputs:
    file1:
        type: File
    file2:
        type: File
    file3:
        type: File
    file4:
        type: File

outputs:
    dirs:
        type: Directory[]

expression: |-
    ${
    var dirs = [];
    dirs.push({
        "class": "Directory",
        "basename": inputs.file1.nameroot + "_1",
        "listing": [inputs.file1, inputs.file2]
    });
    dirs.push({
        "class": "Directory",
        "basename": inputs.file1.nameroot + "_2",
        "listing": [inputs.file3, inputs.file4]
    });
    return {"dirs": dirs};
    }