More text for lesson 5. Working on formatting.
[rnaseq-cwl-training.git] / lesson5 / lesson5.md
1 # Expressions
2
3 1. Expressions on step inputs
4
5 You might have noticed that the output bam files are all named
6 `Aligned.sortedByCoord.out.bam`.  This happens because because when we
7 call STAR, it gives the output a default file name.
8
9 During workflow execution, this is usually not a problem.  The
10 workflow runner is smart enough to know that these files are different
11 and keep them separate.  This can even make development easier by not
12 having to worry about assigning unique file names to every file.
13
14 However, it is a problem for humans interpreting the output.  We can
15 fix this by setting the parameter `OutFileNamePrefix` on STAR.  We
16 want the output filename to be based on the input filename.
17
18 In `alignment.cwl`, we can use `valueFrom` on the `OutFileNamePrefix`
19 input parameter to construct the output prefix from the input
20 filename.
21
22 ```
23 requirements:
24   StepInputExpressionRequirement: {}
25 steps:
26   ...
27   STAR:
28     ...
29     in:
30       ForwardReads: fq
31       ...
32       OutFileNamePrefix: {valueFrom: "$(inputs.ForwardReads.nameroot)."}
33 ```
34
35 The code between `$(...)` is called an "expression".  It is evaluated
36 when setting up the step to run, and the expression is replaced by the
37 result to get the parameter value.
38
39 An expression can refer to other inputs to the step that are either
40 directly connected to another value, or have a default value.  Here,
41 we refer to the input parameter ForwardReads, which is our fastq input
42 file.
43
44 ForwardReads is a File object, not a plain file name, so it has some
45 fields of its own.  The file object has a number of fields that we can
46 use.  These include `basename` (the name of the file, without a
47 directory), `size` (file size, in bytes), `nameext` (the last file
48 extension) and `nameroot` (the name with `nameext` removed).  Using
49
50 Finally, our expression is embedded in a string, so after replacing
51 the expression with the value of `inputs.ForwardReads.nameroot`, it
52 adds the remainder of the string, which just is a dot `.`.  This is to
53 separate the leading part of our filename from the "Aligned.bam"
54 extension that will be added by STAR.
55
56 2. Organizing output files into Directories
57
58 You probably noticed that all the output files appear in the same
59 directory.  You might prefer that each file appears in its own
60 directory.  This will show you how to do that.
61
62 Unlike shell scripts, in CWL you cannot call `mkdir` and `mv` to
63 organize files into directories.  This is because the output files, at
64 this point, do not actually exist together in one directory.  They may
65 exist on different nodes, in different directories, or different cloud
66 buckets.  In CWL, instead of moving files around directly, you tell
67 the runner you want your directory to look like, and it will create it
68 for you.
69
70 We can use an "expression" to create a `Directory` object describing
71 each of our directories.  An expression is a piece of Javascript code
72 which is executed by the workflow runner to produce values that affect
73 the workflow.  These can be a simple as substituting the value of an
74 input variable, or as complex as en entire function that generates new
75 objects.
76
77 Javscript code must be bracketed inside `$(...)` or `${...}`. The
78 difference comes down to syntax.  The `$()` form is more compact but
79 can only include code that can appear on the right side of an
80 assignment (`=`), which cannot include control blocks like `if` or
81 `for`.  The `${}` form is a Javascript function, which can include
82 control blocks, and must end in a `return` statement.
83
84 Dxpressions can both appear in `valueFrom` fields as well as some
85 other fields, or in an `ExpressionTool` which, like `Workflow` or
86 `CommandLineTool` has explicitly defined `inputs` and `outputs`
87 sections.
88
89 The approach here is to define an expression tool which takes a
90
91 The `Directory` object has two fields, `basename` and `listing`.  The
92 `basename` is the name of the directory, and the `listing` is the
93 contents, which consists of other File and Directory objects.
94
95 Create `subdirs.cwl`:
96
97 ```
98 cwlVersion: v1.2
99 class: ExpressionTool
100 requirements:
101   InlineJavascriptRequirement: {}
102 inputs:
103   fq: File[]
104   bams: File[]
105   qc: File[]
106 outputs:
107   dirs: Directory[]
108 expression: |-
109   ${
110   var dirs = [];
111   for (var i = 0; i < inputs.bams.length; i++) {
112     dirs.push({
113       "class": "Directory",
114       "basename": inputs.fq[i].nameroot,
115       "listing": [inputs.bams[i], inputs.qc[i]]
116     });
117   }
118   return {"dirs": dirs};
119   }
120 ```
121
122 Then change `main.cwl`:
123
124 ```
125 steps:
126   ...
127   output-subdirs:
128     run: subdirs.cwl
129     in:
130       fq: fq
131       bams: alignment/bam_sorted_indexed
132       qc: alignment/qc_html
133     out: [dirs]
134 outputs:
135   dirs:
136     type: Directory[]
137     outputSource: output-subdirs/dirs
138   featurecounts:
139     type: File
140     outputSource: featureCounts/featurecounts
141 ```
142
143 3. Other uses for expressions
144
145 - Creating configuration files on the fly.