Skip to content

Commit 604ee34

Browse files
committed
Add nimble/bulk step
1 parent b084e00 commit 604ee34

File tree

3 files changed

+178
-2
lines changed

3 files changed

+178
-2
lines changed

singlecell/src/org/labkey/singlecell/SingleCellModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
import org.labkey.singlecell.run.CellRangerVDJWrapper;
115115
import org.labkey.singlecell.run.NimbleAlignmentStep;
116116
import org.labkey.singlecell.run.NimbleAnalysis;
117+
import org.labkey.singlecell.run.NimbleBulkAlignmentStep;
117118
import org.labkey.singlecell.run.RepeatNimbleReportHandler;
118119
import org.labkey.singlecell.run.VelocytoAlignmentStep;
119120
import org.labkey.singlecell.run.VelocytoAnalysisStep;
@@ -219,6 +220,7 @@ public static void registerPipelineSteps()
219220
SequencePipelineService.get().registerPipelineStep(new CellRangerVDJWrapper.VDJProvider());
220221
SequencePipelineService.get().registerPipelineStep(new NimbleAlignmentStep.Provider());
221222
SequencePipelineService.get().registerPipelineStep(new NimbleAnalysis.Provider());
223+
SequencePipelineService.get().registerPipelineStep(new NimbleBulkAlignmentStep.Provider());
222224
SequencePipelineService.get().registerPipelineStep(new VelocytoAlignmentStep.Provider());
223225
SequencePipelineService.get().registerPipelineStep(new VelocytoAnalysisStep.Provider());
224226

singlecell/src/org/labkey/singlecell/run/NimbleAnalysis.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package org.labkey.singlecell.run;
22

3+
import htsjdk.samtools.SAMFileHeader;
4+
import htsjdk.samtools.SAMTag;
5+
import htsjdk.samtools.SamReaderFactory;
36
import org.labkey.api.pipeline.PipelineJobException;
47
import org.labkey.api.sequenceanalysis.model.AnalysisModel;
58
import org.labkey.api.sequenceanalysis.model.Readset;
@@ -29,7 +32,7 @@ public static class Provider extends AbstractAnalysisStepProvider<NimbleAnalysis
2932
{
3033
public Provider()
3134
{
32-
super("NimbleAnalysis", "Nimble", null, "This will run Nimble to generate a supplemental feature count matrix for the provided libraries", NimbleAlignmentStep.getToolParameters(), new LinkedHashSet<>(PageFlowUtil.set("sequenceanalysis/field/GenomeField.js", "singlecell/panel/NimbleAlignPanel.js")), null);
35+
super("NimbleAnalysis", "Nimble", null, "This will run Nimble to generate a supplemental feature count matrix for the provided libraries. This should work using either CellRanger/scRNA-seq or bulk input data.", NimbleAlignmentStep.getToolParameters(), new LinkedHashSet<>(PageFlowUtil.set("sequenceanalysis/field/GenomeField.js", "singlecell/panel/NimbleAlignPanel.js")), null);
3336
}
3437

3538
@Override
@@ -58,7 +61,15 @@ public Output performAnalysisPerSampleRemote(Readset rs, File inputBam, Referenc
5861
NimbleHelper helper = new NimbleHelper(getPipelineCtx(), getProvider(), getStepIdx());
5962
helper.doNimbleAlign(inputBam, output, rs, FileUtil.getBaseName(inputBam));
6063

61-
NimbleHelper.write10xBarcodes(inputBam, getPipelineCtx().getLogger(), rs, referenceGenome, output);
64+
SAMFileHeader header = SamReaderFactory.makeDefault().getFileHeader(inputBam);
65+
if (header.getAttribute(SAMTag.CB.name()) != null)
66+
{
67+
NimbleHelper.write10xBarcodes(inputBam, getPipelineCtx().getLogger(), rs, referenceGenome, output);
68+
}
69+
else
70+
{
71+
getPipelineCtx().getLogger().info("BAM lacks CB tag, will not output 10x barcodes to file");
72+
}
6273

6374
return output;
6475
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package org.labkey.singlecell.run;
2+
3+
import org.apache.logging.log4j.Logger;
4+
import org.jetbrains.annotations.Nullable;
5+
import org.labkey.api.pipeline.PipelineJobException;
6+
import org.labkey.api.sequenceanalysis.model.Readset;
7+
import org.labkey.api.sequenceanalysis.pipeline.AbstractAnalysisStepProvider;
8+
import org.labkey.api.sequenceanalysis.pipeline.AlignmentOutputImpl;
9+
import org.labkey.api.sequenceanalysis.pipeline.AlignmentStep;
10+
import org.labkey.api.sequenceanalysis.pipeline.AlignmentStepProvider;
11+
import org.labkey.api.sequenceanalysis.pipeline.PipelineContext;
12+
import org.labkey.api.sequenceanalysis.pipeline.ReferenceGenome;
13+
import org.labkey.api.sequenceanalysis.pipeline.SamtoolsRunner;
14+
import org.labkey.api.sequenceanalysis.pipeline.SequenceAnalysisJobSupport;
15+
import org.labkey.api.sequenceanalysis.pipeline.SequencePipelineService;
16+
import org.labkey.api.sequenceanalysis.run.AbstractAlignmentPipelineStep;
17+
import org.labkey.api.sequenceanalysis.run.AbstractCommandWrapper;
18+
import org.labkey.api.util.FileUtil;
19+
import org.labkey.api.util.PageFlowUtil;
20+
21+
import java.io.File;
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.LinkedHashSet;
25+
import java.util.List;
26+
27+
public class NimbleBulkAlignmentStep extends AbstractAlignmentPipelineStep<NimbleBulkAlignmentStep.NimbleBulkWrapper> implements AlignmentStep
28+
{
29+
public static class Provider extends AbstractAnalysisStepProvider<NimbleAnalysis>
30+
{
31+
public Provider()
32+
{
33+
super("NimbleBulkAnalysis", "Nimble (Bulk)", null, "This will run Nimble to generate a supplemental feature count matrix for the provided libraries. This version is intended for bulk input data. Please use the CellRanger/Nimble version for scRNA-seq", NimbleAlignmentStep.getToolParameters(), new LinkedHashSet<>(PageFlowUtil.set("sequenceanalysis/field/GenomeField.js", "singlecell/panel/NimbleAlignPanel.js")), null);
34+
}
35+
36+
@Override
37+
public NimbleAnalysis create(PipelineContext ctx)
38+
{
39+
return new NimbleAnalysis(this, ctx);
40+
}
41+
}
42+
43+
public NimbleBulkAlignmentStep(AlignmentStepProvider<?> provider, PipelineContext ctx, NimbleBulkAlignmentStep.NimbleBulkWrapper wrapper)
44+
{
45+
super(provider, ctx, wrapper);
46+
}
47+
48+
@Override
49+
public IndexOutput createIndex(ReferenceGenome referenceGenome, File outputDir) throws PipelineJobException
50+
{
51+
return null;
52+
}
53+
54+
@Override
55+
public void init(SequenceAnalysisJobSupport support) throws PipelineJobException
56+
{
57+
NimbleHelper helper = new NimbleHelper(getPipelineCtx(), getProvider(), getStepIdx());
58+
59+
List<Integer> genomeIds = helper.getGenomeIds();
60+
for (int id : genomeIds)
61+
{
62+
helper.prepareGenome(id);
63+
}
64+
}
65+
66+
@Override
67+
public AlignmentOutput performAlignment(Readset rs, List<File> inputFastqs1, @Nullable List<File> inputFastqs2, File outputDirectory, ReferenceGenome referenceGenome, String basename, String readGroupId, @Nullable String platformUnit) throws PipelineJobException
68+
{
69+
AlignmentOutputImpl output = new AlignmentOutputImpl();
70+
SamtoolsRunner st = new SamtoolsRunner(getPipelineCtx().getLogger());
71+
72+
List<File> outputBams = new ArrayList<>();
73+
int bamIdx = 0;
74+
while (bamIdx < inputFastqs1.size())
75+
{
76+
File outputBam = new File(getPipelineCtx().getWorkingDirectory(), FileUtil.makeLegalName(rs.getName()) + ".unmapped." + bamIdx + ".bam");
77+
List<String> args = new ArrayList<>(Arrays.asList(st.getSamtoolsPath().getPath(), "import", "-o", outputBam.getPath(), "-r", "ID:" + readGroupId));
78+
if (inputFastqs2 == null || inputFastqs2.isEmpty())
79+
{
80+
args.add("-O");
81+
args.add(inputFastqs1.get(bamIdx).getPath());
82+
}
83+
else
84+
{
85+
args.add("-1");
86+
args.add(inputFastqs1.get(bamIdx).getPath());
87+
88+
if (bamIdx > inputFastqs2.size())
89+
{
90+
throw new PipelineJobException("Unequal lengths for first/second pair FASTQs");
91+
}
92+
93+
args.add("-2");
94+
args.add(inputFastqs2.get(bamIdx).getPath());
95+
}
96+
bamIdx++;
97+
98+
st.execute(args);
99+
outputBams.add(outputBam);
100+
}
101+
102+
File outputBam;
103+
if (outputBams.size() > 1)
104+
{
105+
outputBam = new File(getPipelineCtx().getWorkingDirectory(), FileUtil.makeLegalName(rs.getName()) + ".unmapped.bam");
106+
outputBams.forEach(output::addIntermediateFile);
107+
108+
List<String> args = new ArrayList<>(Arrays.asList(st.getSamtoolsPath().getPath(), "merge", "-o", outputBam.getPath(), "-f"));
109+
Integer maxThreads = SequencePipelineService.get().getMaxThreads(getPipelineCtx().getLogger());
110+
if (maxThreads != null)
111+
{
112+
args.add("-@");
113+
args.add(maxThreads.toString());
114+
}
115+
116+
outputBams.forEach(bam -> args.add(bam.getPath()));
117+
st.execute(args);
118+
}
119+
else
120+
{
121+
outputBam = outputBams.get(0);
122+
}
123+
124+
// Now run nimble itself:
125+
NimbleHelper helper = new NimbleHelper(getPipelineCtx(), getProvider(), getStepIdx());
126+
helper.doNimbleAlign(outputBam, output, rs, basename);
127+
output.setBAM(outputBam);
128+
129+
return output;
130+
}
131+
132+
@Override
133+
public boolean doAddReadGroups()
134+
{
135+
return false;
136+
}
137+
138+
@Override
139+
public boolean doSortIndexBam()
140+
{
141+
return false;
142+
}
143+
144+
@Override
145+
public boolean alwaysCopyIndexToWorkingDir()
146+
{
147+
return false;
148+
}
149+
150+
@Override
151+
public boolean supportsGzipFastqs()
152+
{
153+
return true;
154+
}
155+
156+
public static class NimbleBulkWrapper extends AbstractCommandWrapper
157+
{
158+
public NimbleBulkWrapper(Logger log)
159+
{
160+
super(log);
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)