cwltool をインストールして、実際にCWLを実行してみる

追記:2019-01-31 一部更新
追記:2020-08-11 一部更新


アドベントカレンダー３日目、かきかけなのですが、、、

dockerがあると、便利ですが、dockerがなくても動かすことができます。
今回の記事はdockerは必要がありません。

# cwltool をインストールして、実際にCWLを実行してみる

## インストール

まずは、インストールですが、既存の環境にいきなりいれると、いろいろ競合（コンフリクト）するかもしれないので、クリーンなところに、インストールして試すのがおすすめです。

もちろん、condaなどを使って入れても良いですし、仮想マシンを作ってみるという方法でもよいです。

こんかいは、venv(virtualenv)を使う方法を紹介します。
プロジェクトのco-founderの、マイケルさんも、この方法をよく使っているそうです。


Python3 系

```
python -m venv cwltoolenv
```

Python2 系

```
python -m virtualenv cwltoolenv
```

venv環境にはいるには、以下のコマンドです。

```
. cwltoolenv/bin/activate
```

venv環境にはいると、こんなかんじに、`(cwltoolenv)` というのが、プロンプトの手前につくようになると思います。

```
(cwltoolenv) $
```


脱出する方法は、以下のコマンドです。

```
deactivate
```

activateした直後に、モジュールのリストを確認すると、
すると、こんなかんじに、ほぼからっぽだとおもいます。

```
$ pip list
Package    Version
---------- -------
pip        10.0.1 
setuptools 39.0.1
```

# cwltoolをインストールする

実際に、cwltoolをインストールしてみましょう

```
pip install cwltool
```

インストールできたら、バージョンを確認してみましょう。

```
$ cwltool --version
/Users/manabu/cwldocs/cwltoolenv/bin/cwltool 1.0.20181201184214
```


pip listで、入ったモジュールを確認してみると、以下のような感じになります(2018-12-11)。

```
$ pip list
Package           Version           
----------------- ------------------
bagit             1.7.0             
CacheControl      0.11.7            
certifi           2018.11.29        
chardet           3.0.4             
cwltool           1.0.20181201184214
decorator         4.3.0             
idna              2.8               
isodate           0.6.0             
lockfile          0.12.2            
lxml              4.2.5             
mistune           0.8.4             
mypy-extensions   0.4.1             
networkx          2.2               
pip               10.0.1            
prov              1.5.1             
psutil            5.4.8             
pyparsing         2.3.0             
python-dateutil   2.7.5             
rdflib            4.2.2             
rdflib-jsonld     0.4.0             
requests          2.21.0            
ruamel.yaml       0.15.77           
scandir           1.9.0             
schema-salad      3.0.20181129082112
setuptools        39.0.1            
shellescape       3.4.1             
six               1.12.0            
subprocess32      3.5.3             
typing-extensions 3.6.6             
urllib3           1.24.1
```

最初のサンプルとしては、
あるテキストファイルから、特定の文字列を抜き出し、それがいくつあるかを数えるというサンプルを動かしてみましょう。

```
#!/usr/bin/env cwl-runner
class: CommandLineTool
cwlVersion: v1.0

inputs:
  pattern:
    type: string
    inputBinding: {position: 0}
  file_to_search:
    type: File
    inputBinding: {position: 1}

outputs:
  results: stdout

baseCommand: grep
```

文法がただしいかなどを確認してみましょう。
`cwltool --validate CWLファイル` で確認できます。

```
cwltool --validate grep.cwl 
/Users/manabu/cwldocs/cwltoolenv/bin/cwltool 1.0.20181201184214
Resolved 'grep.cwl' to 'file:///Users/manabu/cwldocs/grep.cwl'
grep.cwl is valid CWL.
```

実行するときに指定するべきパラメータが、何であるかを確認しましょう。

```
$ cwltool grep.cwl --help
/Users/manabu/cwldocs/cwltoolenv/bin/cwltool 1.0.20181201184214
Resolved 'grep.cwl' to 'file:///Users/manabu/cwldocs/grep.cwl'
usage: grep.cwl [-h] --file_to_search FILE_TO_SEARCH --pattern PATTERN
                [job_order]

positional arguments:
  job_order             Job input json file

optional arguments:
  -h, --help            show this help message and exit
  --file_to_search FILE_TO_SEARCH
  --pattern PATTERN
```


次に、文字をカウントするものを作ります。

```
#!/usr/bin/env cwl-runner
class: CommandLineTool
cwlVersion: v1.0

inputs:
  files:
    type: File[]
    inputBinding: {position: 1}
    streamable: true

baseCommand: [wc, -l]

outputs:
  counts: stdout
```

文法的に正しいかをチェックします。

```
$ cwltool --validate wc.cwl
/Users/manabu/cwldocs/cwltoolenv/bin/cwltool 1.0.20181201184214
Resolved 'wc.cwl' to 'file:///Users/manabu/cwldocs/wc.cwl'
wc.cwl is valid CWL.

```

次に、必要なパラメータを確認してみましょう。

```
$ cwltool wc.cwl --help
/Users/manabu/cwldocs/cwltoolenv/bin/cwltool 1.0.20181201184214
Resolved 'wc.cwl' to 'file:///Users/manabu/cwldocs/wc.cwl'
usage: wc.cwl [-h] --files FILES [job_order]

positional arguments:
  job_order      Job input json file

optional arguments:
  -h, --help     show this help message and exit
  --files FILES
```

実際に実行してみましょう。

```
cwltool wc.cwl --files grepresult.txt
```

最後にまとめて実行するものを作ります。

このときの注意点として、
`grep.cwl` は、このファイルだけでは、入力ファイルを１つしか受け付けません。
また出力も一つのファイルです。
一方
`wc.cwl` は、複数のファイルを入力に受け付けるようになっています。
このような場合は、`grep.cwl` の出力を、そのまま`wc.cwl` に渡すと
`File` を `File[]` に渡そうとするエラーがでます。

簡単な解決策は、`wc.cwl`の入力を、１のファイルだけにするように書き換える方法になります。

しかし、別の解決策もあり、そちらの方が、他の人のコマンドラインツールやーワークフローを再利用するという点では、実用的かもしれませんので、その方法を紹介します。

その方法のコンセプトは、 `File []`　で受けた複数のファイルを、ファイルごとに分けて、 `File` を入力にするコマンドラインツールにわたすということになります。

具体的に今回のケースですと
`grep-and-wc.cwl`  
の入力を`File []`にする。
この `File []` で受けた入力ファイル群を、
`ScatterFeatureRequirement` を使って、
`grep.cwl` に渡すとなります。

この場合、`grep.cwl` はひとつづつファイルを受け取りますが、
`wc.cwl` には、その出力がまとめられて `File []` として渡されてます。

```
#!/usr/bin/env cwl-runner
class: Workflow
cwlVersion: v1.0

requirements:
  - class: ScatterFeatureRequirement
inputs:
  pattern: string
  file_to_search: File[]

outputs:
  outfile:
    type: File
    outputSource: wc/counts

steps:
  grep:
    run: grep.cwl
    in:
      pattern: pattern
      file_to_search: file_to_search
    scatter: file_to_search
    out: [results]

  wc:
    run: wc.cwl
    in:
      files: grep/results
    out: [counts]
```

```console

cwltool --validate　grep-and-wc.cwl
```

実際の実行例

```console
$  cwltool grep-wc.cwl \
 --file_to_search wc.cwl　\
 --file_to_search grep.cwl \
 --pattern c

```

```console
$ cat 2cf0660f567a08c2788a59b57c1a705e60ef0c5f 
       5 /private/var/folders/zj/zd82d3pn26d1rx8c5qmqrk140000gn/T/tmp40gof4jc/stga222ac11-66a4-4176-8e9d-6b00a6f09374/1ec653ec28a423e896935c5fde7aad35856205bb
       4 /private/var/folders/zj/zd82d3pn26d1rx8c5qmqrk140000gn/T/tmp40gof4jc/stg21849d3e-64ae-42f4-9407-cf551900cc0d/1ec653ec28a423e896935c5fde7aad35856205bb
       9 total
```