Skip to content

Commit 1bf0716

Browse files
authored
Merge pull request #1186 from fls-bioinformatics-core/make_fastqs-no-undetermined
Add '--no-undetermined-fastqs' option to the 'make_fastqs' command
2 parents 281e182 + 8d53071 commit 1bf0716

7 files changed

Lines changed: 297 additions & 11 deletions

File tree

auto_process_ngs/bcl2fastq/pipeline.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
'i2_length',
125125
'override_template',
126126
'no_lane_splitting',
127+
'no_undetermined_fastqs',
127128
'tenx_filter_single_index',
128129
'tenx_filter_dual_index',
129130
'spaceranger_rc_i2_override',
@@ -355,6 +356,7 @@ def __init__(self,run_dir,sample_sheet,protocol='standard',
355356
self.add_param('find_adapters_with_sliding_window',value=False,
356357
type=bool)
357358
self.add_param('create_empty_fastqs',value=False,type=bool)
359+
self.add_param('no_undetermined_fastqs',value=False,type=bool)
358360
self.add_param('ignore_missing_bcls',value=False,type=bool)
359361
self.add_param('name',type=str)
360362
self.add_param('stats_file',type=str)
@@ -484,6 +486,7 @@ def __init__(self,run_dir,sample_sheet,protocol='standard',
484486
adapter_sequence=self._adapter_sequence,
485487
adapter_sequence2=self._adapter_sequence_read2,
486488
no_lane_splitting=self.params.no_lane_splitting,
489+
no_undetermined_fastqs=self.params.no_undetermined_fastqs,
487490
create_fastq_for_index_read=\
488491
self.params.create_fastq_for_index_read,
489492
find_adapters_with_sliding_window=\
@@ -1086,6 +1089,11 @@ def _build_pipeline(self):
10861089
create_fastq_for_index_read = \
10871090
subset['create_fastq_for_index_read']
10881091

1092+
#########################
1093+
# No undetermined Fastqs
1094+
#########################
1095+
no_undetermined_fastqs = subset['no_undetermined_fastqs']
1096+
10891097
# Use sliding window for adapter trimming
10901098
find_adapters_with_sliding_window = \
10911099
subset['find_adapters_with_sliding_window']
@@ -1200,6 +1208,7 @@ def _build_pipeline(self):
12001208
no_lane_splitting=self.params.no_lane_splitting,
12011209
create_fastq_for_index_read=\
12021210
create_fastq_for_index_read,
1211+
no_undetermined_fastqs=no_undetermined_fastqs,
12031212
find_adapters_with_sliding_window=\
12041213
find_adapters_with_sliding_window,
12051214
create_empty_fastqs=self.params.create_empty_fastqs,
@@ -1284,6 +1293,7 @@ def _build_pipeline(self):
12841293
create_fastq_for_index_read=\
12851294
create_fastq_for_index_read,
12861295
create_empty_fastqs=False,
1296+
no_undetermined_fastqs=no_undetermined_fastqs,
12871297
ignore_missing_fastqs=True,
12881298
platform=identify_platform.output.platform,
12891299
bclconvert_exe=\
@@ -1342,6 +1352,8 @@ def _build_pipeline(self):
13421352
create_fastq_for_index_read,
13431353
create_empty_fastqs=\
13441354
self.params.create_empty_fastqs,
1355+
no_undetermined_fastqs=\
1356+
self.params.no_undetermined_fastqs,
13451357
platform=identify_platform.output.platform,
13461358
bclconvert_exe=\
13471359
get_bclconvert.output.bclconvert_exe,
@@ -1684,9 +1696,9 @@ def run(self,analysis_dir,out_dir=None,barcode_analysis_dir=None,
16841696
primary_data_dir=None,force_copy_of_primary_data=False,
16851697
no_lane_splitting=None,create_fastq_for_index_read=None,
16861698
find_adapters_with_sliding_window=None,
1687-
create_empty_fastqs=None,ignore_missing_bcls=None,
1688-
name=None,stats_file=None,stats_full=None,
1689-
per_lane_stats=None,per_lane_sample_stats=None,
1699+
create_empty_fastqs=None, no_undetermined_fastqs=None,
1700+
ignore_missing_bcls=None, name=None,stats_file=None,
1701+
stats_full=None, per_lane_stats=None,per_lane_sample_stats=None,
16901702
nprocessors=None,cellranger_jobmode='local',
16911703
cellranger_mempercore=None,cellranger_maxjobs=None,
16921704
cellranger_jobinterval=None,cellranger_localcores=None,
@@ -1722,6 +1734,8 @@ def run(self,analysis_dir,out_dir=None,barcode_analysis_dir=None,
17221734
sequences (--find-adapters-with-sliding-window)
17231735
create_empty_fastqs (bool): if True then create empty
17241736
"placeholder" Fastqs if not created by bcl2fastq
1737+
no_undetermined_fastqs (bool): if True then don't keep
1738+
the "undetermined" Fastqs if created
17251739
ignore_missing_bcls (bool): if True then ignore missing
17261740
or corrupted BCL files
17271741
name (str): optional identifier for output
@@ -1905,6 +1919,7 @@ def run(self,analysis_dir,out_dir=None,barcode_analysis_dir=None,
19051919
'find_adapters_with_sliding_window':
19061920
find_adapters_with_sliding_window,
19071921
'create_empty_fastqs': create_empty_fastqs,
1922+
'no_undetermined_fastqs': no_undetermined_fastqs,
19081923
'ignore_missing_bcls': ignore_missing_bcls,
19091924
'name': name,
19101925
'stats_file': stats_file,
@@ -2391,7 +2406,7 @@ def init(self,run_dir,out_dir,sample_sheet,bases_mask=None,
23912406
mask_short_adapter_reads=None,
23922407
create_fastq_for_index_read=False,
23932408
find_adapters_with_sliding_window=False,nprocessors=None,
2394-
create_empty_fastqs=False,
2409+
create_empty_fastqs=False, no_undetermined_fastqs=False,
23952410
platform=None,bcl2fastq_exe=None,bcl2fastq_version=None,
23962411
skip_bcl2fastq=False,conda_pkgs=None):
23972412
"""
@@ -2414,6 +2429,9 @@ def init(self,run_dir,out_dir,sample_sheet,bases_mask=None,
24142429
create_fastq_for_index_read (boolean): if True then
24152430
also create Fastq files for index reads (default,
24162431
don't create index read Fastqs)
2432+
no_undetermined_fastqs (bool): if True then don't
2433+
keep any 'undetermined' Fastq files (default, do
2434+
keep the 'undetermined' Fastqs)
24172435
find_adapters_with_sliding_window (bool): if True
24182436
then use sliding window algorith for identifying
24192437
adapter sequences (default is to use string
@@ -2600,6 +2618,17 @@ def finish(self):
26002618
# Terminate with an exception
26012619
raise Exception("Failed to verify outputs against "
26022620
"samplesheet")
2621+
# Remove undetermined Fastqs
2622+
if self.args.no_undetermined_fastqs:
2623+
illumina_data = IlluminaData(os.path.dirname(self.tmp_out_dir),
2624+
os.path.basename(self.tmp_out_dir))
2625+
if illumina_data.undetermined:
2626+
print("Removing undetermined fastqs")
2627+
for undetermined_sample in illumina_data.undetermined.samples:
2628+
for fq in undetermined_sample.fastq:
2629+
fq = os.path.join(undetermined_sample.dirn, fq)
2630+
if os.path.exists(fq):
2631+
os.remove(fq)
26032632
# Move to final location
26042633
print("Moving output to final location: %s" % self.args.out_dir)
26052634
os.rename(self.tmp_out_dir,self.args.out_dir)
@@ -2613,9 +2642,9 @@ def init(self,run_dir,out_dir,sample_sheet,lane=None,bases_mask=None,
26132642
minimum_trimmed_read_length=None,
26142643
mask_short_adapter_reads=None,
26152644
create_fastq_for_index_read=False,nprocessors=None,
2616-
create_empty_fastqs=False,ignore_missing_fastqs=False,
2617-
platform=None,bclconvert_exe=None,bclconvert_version=None,
2618-
skip_bclconvert=False):
2645+
create_empty_fastqs=False, no_undetermined_fastqs=False,
2646+
ignore_missing_fastqs=False, platform=None, bclconvert_exe=None,
2647+
bclconvert_version=None, skip_bclconvert=False):
26192648
"""
26202649
Initialise the RunBclConvert task
26212650
@@ -2636,6 +2665,8 @@ def init(self,run_dir,out_dir,sample_sheet,lane=None,bases_mask=None,
26362665
create_fastq_for_index_read (boolean): if True then
26372666
also create Fastq files for index reads (default,
26382667
don't create index read Fastqs)
2668+
no_undetermined_fastqs (bool): if True then don't
2669+
create 'undetermined' Fastq files
26392670
nprocessors (int): number of processors to use
26402671
(taken from job runner by default)
26412672
create_empty_fastqs (bool): if True then create empty
@@ -2869,6 +2900,17 @@ def finish(self):
28692900
# Terminate with an exception
28702901
raise Exception("Failed to verify outputs against "
28712902
"samplesheet")
2903+
# Remove undetermined Fastqs
2904+
if self.args.no_undetermined_fastqs:
2905+
illumina_data = IlluminaData(os.path.dirname(self.tmp_out_dir),
2906+
os.path.basename(self.tmp_out_dir))
2907+
if illumina_data.undetermined:
2908+
print("Removing undetermined fastqs")
2909+
for undetermined_sample in illumina_data.undetermined.samples:
2910+
for fq in undetermined_sample.fastq:
2911+
fq = os.path.join(undetermined_sample.dirn, fq)
2912+
if os.path.exists(fq):
2913+
os.remove(fq)
28722914
# Move to final location
28732915
print("Moving output to final location: %s" % self.args.out_dir)
28742916
os.rename(self.tmp_out_dir,self.args.out_dir)

auto_process_ngs/cli/auto_process.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,13 @@ def add_make_fastqs_command(cmdparser):
453453
dest='create_fastq_for_index_read',
454454
default=False,
455455
help="also create FASTQs for index reads")
456+
# Don't include 'undetermined' Fastqs
457+
bcl_to_fastq.add_argument('--no-undetermined-fastqs',
458+
action='store_true',
459+
dest='no_undetermined_fastqs',
460+
default=False,
461+
help="don't create or keept the 'undetermined' FASTQs "
462+
"with unassigned reads from demultiplexing")
456463
# Ignore missing or corrupted BCL files
457464
bcl_to_fastq.add_argument("--ignore-missing-bcls", action="store_true",
458465
dest="ignore_missing_bcls", default=False,
@@ -1639,6 +1646,7 @@ def make_fastqs(args):
16391646
adapter_sequence=args.adapter_sequence,
16401647
adapter_sequence_read2=args.adapter_sequence_read2,
16411648
create_fastq_for_index_read=args.create_fastq_for_index_read,
1649+
no_undetermined_fastqs=args.no_undetermined_fastqs,
16421650
ignore_missing_bcls=args.ignore_missing_bcls,
16431651
find_adapters_with_sliding_window=\
16441652
args.find_adapters_with_sliding_window,

auto_process_ngs/commands/make_fastqs_cmd.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def make_fastqs(ap,protocol='standard',platform=None,
5353
analyse_barcodes=True,barcode_analysis_dir=None,
5454
force_copy_of_primary_data=False,
5555
create_empty_fastqs=False,
56+
no_undetermined_fastqs=False,
5657
ignore_missing_bcls=False,runner=None,
5758
cellranger_jobmode=None,
5859
cellranger_mempercore=None,
@@ -165,6 +166,8 @@ def make_fastqs(ap,protocol='standard',platform=None,
165166
create_empty_fastqs (bool): if True then create empty 'placeholder'
166167
fastq files for any missing fastqs after bcl2fastq
167168
(must have completed with zero exit status)
169+
no_undetermined_fastqs (bool): if True then don't keep the
170+
"undetermined" fastq files
168171
runner (JobRunner): (optional) specify a non-default job runner
169172
to use for fastq generation
170173
cellranger_jobmode (str): (optional) job mode to run cellranger in
@@ -440,6 +443,7 @@ def make_fastqs(ap,protocol='standard',platform=None,
440443
find_adapters_with_sliding_window,
441444
create_empty_fastqs=create_empty_fastqs,
442445
ignore_missing_bcls=ignore_missing_bcls,
446+
no_undetermined_fastqs=no_undetermined_fastqs,
443447
stats_file=stats_file,
444448
per_lane_stats=per_lane_stats_file,
445449
nprocessors=nprocessors,

auto_process_ngs/test/bcl2fastq/pipeline/test_standard_bcl2fastq.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,86 @@ def test_makefastqs_standard_protocol_multiple_lanes_reduced_subset(self):
10321032
os.path.join(analysis_dir,filen)),
10331033
"Missing file: %s" % filen)
10341034

1035+
#@unittest.skip("Skipped")
1036+
def test_makefastqs_standard_protocol_no_undetermined_fastqs(self):
1037+
"""
1038+
MakeFastqs: standard protocol/bcl2fastq: no 'undetermined' Fastqs
1039+
"""
1040+
# Create mock source data
1041+
illumina_run = MockIlluminaRun(
1042+
"171020_M00879_00002_AHGXXXX",
1043+
"miseq",
1044+
top_dir=self.wd)
1045+
illumina_run.create()
1046+
run_dir = illumina_run.dirn
1047+
# Sample sheet
1048+
sample_sheet = os.path.join(self.wd,"SampleSheet.csv")
1049+
with open(sample_sheet,'wt') as fp:
1050+
fp.write(SampleSheets.miseq)
1051+
# Create mock bcl2fastq
1052+
# Check that --create-fastq-for-index-read is set
1053+
MockBcl2fastq2Exe.create(os.path.join(self.bin, "bcl2fastq"))
1054+
os.environ['PATH'] = "%s:%s" % (self.bin,
1055+
os.environ['PATH'])
1056+
# Make an (empty) analysis directory
1057+
analysis_dir = os.path.join(self.wd,"analysis")
1058+
os.mkdir(analysis_dir)
1059+
# Do the test
1060+
p = MakeFastqs(run_dir,sample_sheet)
1061+
status = p.run(analysis_dir,
1062+
no_undetermined_fastqs=True,
1063+
poll_interval=POLL_INTERVAL)
1064+
self.assertEqual(status,0)
1065+
# Check outputs
1066+
self.assertEqual(p.output.platform,"miseq")
1067+
self.assertEqual(p.output.flow_cell_mode,None)
1068+
self.assertEqual(p.output.primary_data_dir,
1069+
os.path.join(analysis_dir,
1070+
"primary_data"))
1071+
self.assertEqual(p.output.bcl2fastq_info,
1072+
(os.path.join(self.bin,"bcl2fastq"),
1073+
"bcl2fastq",
1074+
"2.20.0.422"))
1075+
self.assertEqual(p.output.cellranger_info,None)
1076+
self.assertTrue(p.output.acquired_primary_data)
1077+
self.assertEqual(p.output.stats_file,
1078+
os.path.join(analysis_dir,"statistics.info"))
1079+
self.assertEqual(p.output.stats_full,
1080+
os.path.join(analysis_dir,"statistics_full.info"))
1081+
self.assertEqual(p.output.per_lane_stats,
1082+
os.path.join(analysis_dir,
1083+
"per_lane_statistics.info"))
1084+
self.assertEqual(p.output.per_lane_sample_stats,
1085+
os.path.join(analysis_dir,
1086+
"per_lane_sample_stats.info"))
1087+
self.assertEqual(p.output.seq_len_stats,
1088+
os.path.join(analysis_dir,
1089+
"seq_len_statistics.info"))
1090+
self.assertEqual(p.output.missing_fastqs,[])
1091+
for subdir in (os.path.join("primary_data",
1092+
"171020_M00879_00002_AHGXXXX"),
1093+
"bcl2fastq",
1094+
"barcode_analysis",):
1095+
self.assertTrue(os.path.isdir(
1096+
os.path.join(analysis_dir,subdir)),
1097+
"Missing subdir: %s" % subdir)
1098+
self.assertTrue(os.path.islink(
1099+
os.path.join(analysis_dir,
1100+
"primary_data",
1101+
"171020_M00879_00002_AHGXXXX")))
1102+
for filen in ("statistics.info",
1103+
"statistics_full.info",
1104+
"per_lane_statistics.info",
1105+
"per_lane_sample_stats.info",
1106+
"seq_len_statistics.info",
1107+
"processing_qc.html"):
1108+
self.assertTrue(os.path.isfile(
1109+
os.path.join(analysis_dir,filen)),
1110+
"Missing file: %s" % filen)
1111+
for fq in ["Undetermined_S0_L001_R2_001.fastq.gz"]:
1112+
self.assertFalse(os.path.exists(os.path.join(analysis_dir, "bcl2fastq", fq)),
1113+
f"'{fq}' is present (should be absent)")
1114+
10351115
#@unittest.skip("Skipped")
10361116
def test_makefastqs_standard_protocol_rerun_completed_pipeline(self):
10371117
"""

0 commit comments

Comments
 (0)