Skip to content

Commit 3570d36

Browse files
committed
Add wrapper for Kracken2
1 parent c8ca6a7 commit 3570d36

2 files changed

Lines changed: 197 additions & 1 deletion

File tree

SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
import org.labkey.sequenceanalysis.run.preprocessing.FastqcProcessingStep;
153153
import org.labkey.sequenceanalysis.run.preprocessing.FilterReadsStep;
154154
import org.labkey.sequenceanalysis.run.preprocessing.FlashPipelineStep;
155+
import org.labkey.sequenceanalysis.run.preprocessing.Kracken2Step;
155156
import org.labkey.sequenceanalysis.run.preprocessing.PrintReadsContainingStep;
156157
import org.labkey.sequenceanalysis.run.preprocessing.TagPcrSummaryStep;
157158
import org.labkey.sequenceanalysis.run.preprocessing.TrimmomaticWrapper;
@@ -291,7 +292,7 @@ public static void registerPipelineSteps()
291292
SequencePipelineService.get().registerPipelineStep(new CutadaptWrapper.Provider());
292293
SequencePipelineService.get().registerPipelineStep(new FastqcProcessingStep.Provider());
293294
SequencePipelineService.get().registerPipelineStep(new CutadaptCropWrapper.Provider());
294-
//SequencePipelineService.get().registerPipelineStep(new BlastFilterPipelineStep.Provider());
295+
SequencePipelineService.get().registerPipelineStep(new Kracken2Step.Provider());
295296

296297
//ref library
297298
SequencePipelineService.get().registerPipelineStep(new DNAReferenceLibraryStep.Provider());
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package org.labkey.sequenceanalysis.run.preprocessing;
2+
3+
import org.apache.logging.log4j.Logger;
4+
import org.jetbrains.annotations.Nullable;
5+
import org.json.JSONObject;
6+
import org.labkey.api.pipeline.PipelineJobException;
7+
import org.labkey.api.pipeline.PipelineJobService;
8+
import org.labkey.api.sequenceanalysis.SequenceAnalysisService;
9+
import org.labkey.api.sequenceanalysis.pipeline.AbstractPipelineStepProvider;
10+
import org.labkey.api.sequenceanalysis.pipeline.CommandLineParam;
11+
import org.labkey.api.sequenceanalysis.pipeline.PipelineContext;
12+
import org.labkey.api.sequenceanalysis.pipeline.PipelineStepProvider;
13+
import org.labkey.api.sequenceanalysis.pipeline.PreprocessingStep;
14+
import org.labkey.api.sequenceanalysis.pipeline.SequencePipelineService;
15+
import org.labkey.api.sequenceanalysis.pipeline.ToolParameterDescriptor;
16+
import org.labkey.api.sequenceanalysis.run.AbstractCommandPipelineStep;
17+
import org.labkey.api.sequenceanalysis.run.AbstractCommandWrapper;
18+
import org.labkey.api.sequenceanalysis.run.SimpleScriptWrapper;
19+
import org.labkey.api.util.FileUtil;
20+
import org.labkey.api.util.Pair;
21+
22+
import java.io.File;
23+
import java.util.ArrayList;
24+
import java.util.Arrays;
25+
import java.util.List;
26+
27+
public class Kracken2Step extends AbstractCommandPipelineStep<Kracken2Step.Kracken2Wrapper> implements PreprocessingStep
28+
{
29+
private static final String DB_PARAM = "db";
30+
private static final String MODE_PARAM = "mode";
31+
32+
public Kracken2Step(PipelineStepProvider<?> provider, PipelineContext ctx)
33+
{
34+
super(provider, ctx, new Kracken2Wrapper(ctx.getLogger()));
35+
}
36+
37+
public static class Provider extends AbstractPipelineStepProvider<PreprocessingStep>
38+
{
39+
public Provider()
40+
{
41+
super("Kracken2", "Kracken2", "Kracken2", "This step aligns input reads against a reference using BWA-mem and will only return read pairs without a passing hit in either read.", Arrays.asList(
42+
ToolParameterDescriptor.create(DB_PARAM, "Database", "This determines the DB for positive or negative selection", "ldk-simplecombo", new JSONObject(){{
43+
put("storeValues", "bacteria-viral");
44+
put("multiSelect", false);
45+
put("allowBlank", false);
46+
put("joinReturnValue", true);
47+
put("delimiter", ";");
48+
}}, "bacteria-viral"),
49+
ToolParameterDescriptor.create(MODE_PARAM, "Reads To Retain", "This determines which set of reads is passed to the next step. If 'Retain Classified' is selected, then reads matching the DB are retained. if 'Retain Unclassified' is selected, then reads that do not match the DB are retained", "ldk-simplecombo", new JSONObject(){{
50+
put("storeValues", "Classified;Unclassified");
51+
put("multiSelect", false);
52+
put("allowBlank", false);
53+
put("joinReturnValue", true);
54+
put("delimiter", ";");
55+
}}, null),
56+
ToolParameterDescriptor.createCommandLineParam(CommandLineParam.create("--minimum-hit-groups"), "minimumHitGroups", "Minimum Hit Groups", "Minimum number of hit groups (overlapping k-mers sharing the same minimizer) needed to make a call", "ldk-integerfield", new JSONObject(){{
57+
put("minValue", 0);
58+
}}, 2),
59+
ToolParameterDescriptor.createCommandLineParam(CommandLineParam.create("--confidence"), "confidence", "Confidence", "Confidence score threshold (0-1)", "ldk-numberfield", new JSONObject(){{
60+
put("minValue", 0);
61+
put("maxValue", 1);
62+
put("decimalPrecision", 2);
63+
}}, 0)
64+
), null, "https://github.com/DerrickWood/kraken2");
65+
}
66+
67+
@Override
68+
public Kracken2Step create(PipelineContext context)
69+
{
70+
return new Kracken2Step(this, context);
71+
}
72+
}
73+
74+
@Override
75+
public Output processInputFile(File inputFile, @Nullable File inputFile2, File outputDir) throws PipelineJobException
76+
{
77+
PreprocessingOutputImpl output = new PreprocessingOutputImpl(inputFile, inputFile2);
78+
79+
List<String> args = new ArrayList<>();
80+
args.add(getWrapper().getExe().getPath());
81+
82+
if (inputFile2 != null)
83+
{
84+
args.add("--paired");
85+
}
86+
87+
if (inputFile.getName().toLowerCase().endsWith(".gz"))
88+
{
89+
args.add("--gzip-compressed");
90+
}
91+
92+
Integer threads = SequencePipelineService.get().getMaxThreads(getPipelineCtx().getLogger());
93+
if (threads != null)
94+
{
95+
args.add("--threads");
96+
args.add(threads.toString());
97+
}
98+
99+
String dbName = getProvider().getParameterByName(DB_PARAM).extractValue(getPipelineCtx().getJob(), getProvider(), getStepIdx(), String.class);
100+
if (dbName == null)
101+
{
102+
throw new PipelineJobException("Missing DB name");
103+
}
104+
105+
File binDir = FileUtil.appendName(new File(PipelineJobService.get().getAppProperties().getToolsDirectory()), "kracken2_dbs");
106+
if (!binDir.exists())
107+
{
108+
throw new PipelineJobException("Unable to find kracken2 DB dir, expected: " + binDir.getAbsolutePath());
109+
}
110+
111+
File dbDir = FileUtil.appendName(binDir, dbName);
112+
if (!dbDir.exists())
113+
{
114+
throw new PipelineJobException("Unable to find kracken2 DB dir, expected: " + dbDir.getAbsolutePath());
115+
}
116+
117+
args.add("--use-names");
118+
119+
args.add("--db");
120+
args.add(dbDir.getAbsolutePath());
121+
122+
args.addAll(getClientCommandArgs());
123+
124+
String mode = getProvider().getParameterByName(MODE_PARAM).extractValue(getPipelineCtx().getJob(), getProvider(), getStepIdx(), String.class);
125+
126+
File unclassifiedOutputBase = FileUtil.appendName(outputDir, SequenceAnalysisService.get().getUnzippedBaseName(inputFile.getName()) + ".unclassified");
127+
args.add("--unclassified-out");
128+
args.add(unclassifiedOutputBase.getPath() + "#.fq.gz");
129+
130+
File classifiedOutputBase = FileUtil.appendName(outputDir, SequenceAnalysisService.get().getUnzippedBaseName(inputFile.getName()) + ".classified");
131+
args.add("--classified-out");
132+
args.add(classifiedOutputBase.getPath() + "#.fq.gz");
133+
134+
File reportFile = FileUtil.appendName(outputDir, SequencePipelineService.get().getUnzippedBaseName(inputFile.getName()) + ".kracken2.report.txt");
135+
args.add("--report");
136+
args.add(reportFile.getPath());
137+
138+
args.add(inputFile.getPath());
139+
if (inputFile2 != null)
140+
{
141+
args.add(inputFile2.getPath());
142+
}
143+
144+
getWrapper().execute(args);
145+
146+
File unclassified1 = new File(unclassifiedOutputBase.getPath() + "_1.fq.gz");
147+
File unclassified2 = inputFile2 == null ? null : new File(unclassifiedOutputBase.getPath() + "_2.fq.gz");
148+
149+
File classified1 = new File(classifiedOutputBase.getPath() + "_1.fq.gz");
150+
File classified2 = inputFile2 == null ? null : new File(classifiedOutputBase.getPath() + "_2.fq.gz");
151+
if ("Classified".equals(mode))
152+
{
153+
if (!classified1.exists())
154+
{
155+
throw new PipelineJobException("Classified file does not exist: " + classified1.getAbsolutePath());
156+
}
157+
158+
output.setProcessedFastq(Pair.of(classified1, classified2));
159+
output.addIntermediateFile(unclassified1);
160+
if (unclassified2 != null)
161+
{
162+
output.addIntermediateFile(unclassified2);
163+
}
164+
}
165+
else
166+
{
167+
if (!unclassified1.exists())
168+
{
169+
throw new PipelineJobException("Unclassified file does not exist: " + unclassified1.getAbsolutePath());
170+
}
171+
172+
output.setProcessedFastq(Pair.of(unclassified1, unclassified2));
173+
output.addIntermediateFile(classified1);
174+
if (classified2 != null)
175+
{
176+
output.addIntermediateFile(classified2);
177+
}
178+
}
179+
180+
return output;
181+
}
182+
183+
public static class Kracken2Wrapper extends AbstractCommandWrapper
184+
{
185+
public Kracken2Wrapper(Logger log)
186+
{
187+
super(log);
188+
}
189+
190+
public File getExe()
191+
{
192+
return SimpleScriptWrapper.resolveFileInPath("kracken2", null, true);
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)