Skip to content

Commit 79a1e5c

Browse files
committed
finish multiproc and dwi scan grouping
1 parent 0c5bf18 commit 79a1e5c

File tree

7 files changed

+553
-358
lines changed

7 files changed

+553
-358
lines changed

dmriprep/cli.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@
9898
type=click.FloatRange(min=0, max=1)
9999
)
100100
# specific options for eddy
101+
@click.option(
102+
'--acqp_file',
103+
default=None,
104+
help='If you want to pass in an acqp file for topup/eddy instead of'
105+
'generating it from the json by default.',
106+
type=click.Path(exists=True, dir_okay=False)
107+
)
108+
# workflow configuration
101109
@click.option(
102110
'--nthreads',
103111
default=1,
@@ -112,14 +120,6 @@
112120
help='Maximum number of threads per process',
113121
type=int
114122
)
115-
@click.option(
116-
'--acqp_file',
117-
default=None,
118-
help='If you want to pass in an acqp file for topup/eddy instead of'
119-
'generating it from the json by default.',
120-
type=click.Path(exists=True, dir_okay=False)
121-
)
122-
# workflow configuration
123123
@click.option(
124124
'--ignore',
125125
'-i',
@@ -141,8 +141,10 @@
141141
)
142142
@click.option(
143143
'--write_graph',
144+
is_flag=True,
144145
default=False,
145-
help='Write out nipype workflow graph.'
146+
help='Write out nipype workflow graph.',
147+
type=bool
146148
)
147149
def main(
148150
bids_dir,
@@ -156,9 +158,9 @@ def main(
156158
output_resolution,
157159
bet_dwi,
158160
bet_mag,
161+
acqp_file,
159162
nthreads,
160163
omp_nthreads,
161-
acqp_file,
162164
ignore,
163165
work_dir,
164166
synb0_dir,
@@ -183,13 +185,13 @@ def main(
183185
)
184186

185187
layout = BIDSLayout(bids_dir, validate=True)
186-
all_subjects, subject_list = collect_participants(
188+
subject_list = collect_participants(
187189
layout, participant_label=participant_label
188190
)
189191

190192
if not skip_bids_validation:
191193
from .utils.bids import validate_input_dir
192-
validate_input_dir(bids_dir, all_subjects, subject_list)
194+
validate_input_dir(bids_dir, subject_list)
193195

194196
if not work_dir:
195197
work_dir = os.path.join(output_dir, 'scratch')
@@ -241,8 +243,8 @@ def main(
241243
output_resolution=output_resolution,
242244
bet_dwi=bet_dwi,
243245
bet_mag=bet_mag,
244-
omp_nthreads=omp_nthreads,
245246
acqp_file=acqp_file,
247+
omp_nthreads=omp_nthreads,
246248
ignore=list(ignore),
247249
work_dir=work_dir,
248250
synb0_dir=synb0_dir

dmriprep/utils/bids.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import warnings
77
import json
88
import sys
9+
from pathlib import Path
910

1011
from bids.layout import BIDSLayout
1112

@@ -111,7 +112,7 @@ def collect_participants(
111112
raise exc
112113
warnings.warn(exc.msg, BIDSWarning)
113114

114-
return all_participants, found_label
115+
return found_label
115116

116117

117118
def collect_data(bids_dir, participant_label, concat_dwis, session_label=None):
@@ -142,7 +143,7 @@ def collect_data(bids_dir, participant_label, concat_dwis, session_label=None):
142143

143144
subj_data['dwi'] = group_dwi(subj_data['dwi'], session_label, concat_dwis)
144145

145-
return subj_data, layout
146+
return subj_data
146147

147148

148149
def group_dwi(dwi_files, session_list, concat_dwis):
@@ -158,20 +159,22 @@ def group_dwi(dwi_files, session_list, concat_dwis):
158159
session_groups.append(f)
159160
else:
160161
all_dwis.append(f)
161-
all_dwis.append(session_groups)
162+
if not session_groups == []:
163+
all_dwis.append(session_groups)
162164
else:
163165
session_groups = []
164166
for f in dwi_files:
165167
if any(acq in f for acq in concat_dwis):
166168
session_groups.append(f)
167169
else:
168170
all_dwis.append(f)
169-
all_dwis.append(session_groups)
171+
if not session_groups == []:
172+
all_dwis.append(session_groups)
170173

171174
return all_dwis
172175

173176

174-
def validate_input_dir(bids_dir, all_subjects, subject_list):
177+
def validate_input_dir(bids_dir, subject_list):
175178
# Ignore issues and warnings that should not influence DMRIPREP
176179
import tempfile
177180
import subprocess
@@ -217,7 +220,18 @@ def validate_input_dir(bids_dir, all_subjects, subject_list):
217220
"ignoredFiles": ["/dataset_description.json", "/participants.tsv"],
218221
}
219222
# Limit validation only to data from requested participants
220-
ignored_subjects = all_subjects.difference(subject_list)
223+
if subject_list:
224+
bids_dir = Path(bids_dir)
225+
all_subs = set([s.name[4:] for s in bids_dir.glob('sub-*')])
226+
selected_subs = set([s[4:] if s.startswith('sub-') else s
227+
for s in subject_list])
228+
bad_labels = selected_subs.difference(all_subs)
229+
if bad_labels:
230+
error_msg = 'Data for requested participant(s) label(s) not found. Could ' \
231+
'not find data for participant(s): %s. Please verify the requested ' \
232+
'participant labels.'
233+
raise RuntimeError(error_msg % ','.join(bad_labels))
234+
ignored_subjects = all_subs.difference(selected_subs)
221235
if ignored_subjects:
222236
for subject in ignored_subjects:
223237
validator_config_dict["ignoredFiles"].append("/sub-%s/**" % subject)

dmriprep/workflows/base.py

Lines changed: 86 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def init_dmriprep_wf(
2828
output_resolution,
2929
bet_dwi,
3030
bet_mag,
31-
omp_nthreads,
3231
acqp_file,
32+
omp_nthreads,
3333
ignore,
3434
work_dir,
3535
synb0_dir
@@ -55,8 +55,8 @@ def init_dmriprep_wf(
5555
output_resolution=(1, 1, 1),
5656
bet_dwi=0.3,
5757
bet_mag=0.3,
58-
omp_nthreads=1,
5958
acqp_file='',
59+
omp_nthreads=1,
6060
ignore=[],
6161
work_dir='.',
6262
synb0_dir=''
@@ -87,13 +87,14 @@ def init_dmriprep_wf(
8787
acqp_file: str
8888
Optionally supply eddy acquisition parameters file
8989
ignore: list
90-
Preprocessing steps to skip (may include 'denoise', 'unring', 'fieldmaps'
90+
Preprocessing steps to skip (may include 'denoise', 'unring', 'fieldmaps')
9191
work_dir: str
9292
Directory in which to store workflow execution state and temporary files
9393
synb0_dir: str
9494
Direction in which synb0 derivatives are saved
9595
9696
"""
97+
9798
dmriprep_wf = pe.Workflow(name='dmriprep_wf')
9899
dmriprep_wf.base_dir = work_dir
99100

@@ -231,47 +232,100 @@ def init_single_subject_wf(
231232
subject_wf = pe.Workflow(name=name)
232233

233234
for dwi_file in subject_data['dwi']:
235+
multiple_dwis = isinstance(dwi_file, list)
236+
237+
if multiple_dwis:
238+
print(dwi_file)
239+
ref_file = dwi_file[0]
240+
241+
from .dwi import init_dwi_concat_wf
242+
243+
dwi_concat_wf = init_dwi_concat_wf(ref_file, dwi_file)
244+
245+
concat_spec = dwi_concat_wf.get_node('inputnode')
246+
concat_spec.inputs.ref_file = ref_file
247+
concat_spec.inputs.dwi_list = dwi_file
248+
concat_spec.inputs.bvec_list = [layout.get_bvec(bvec) for bvec in dwi_file]
249+
concat_spec.inputs.bval_list = [layout.get_bval(bval) for bval in dwi_file]
250+
251+
metadata = layout.get_metadata(ref_file)
252+
253+
dwi_preproc_wf = init_dwi_preproc_wf(
254+
layout=layout,
255+
output_dir=output_dir,
256+
subject_id=subject_id,
257+
dwi_file=dwi_file,
258+
metadata=metadata,
259+
b0_thresh=b0_thresh,
260+
output_resolution=output_resolution,
261+
bet_dwi=bet_dwi,
262+
bet_mag=bet_mag,
263+
omp_nthreads=omp_nthreads,
264+
acqp_file=acqp_file,
265+
ignore=ignore,
266+
synb0_dir=synb0_dir
267+
)
268+
269+
dwi_preproc_wf.base_dir = os.path.join(
270+
os.path.abspath(work_dir), subject_id
271+
)
272+
273+
inputspec = dwi_preproc_wf.get_node('inputnode')
274+
inputspec.inputs.subject_id = subject_id
275+
inputspec.inputs.dwi_meta = metadata
276+
inputspec.inputs.out_dir = os.path.abspath(output_dir)
277+
278+
subject_wf.connect([
279+
(dwi_concat_wf, dwi_preproc_wf, [('outputnode.dwi_file', 'inputnode.dwi_file'),
280+
('outputnode.bvec_file', 'inputnode.bvec_file'),
281+
('outputnode.bval_file', 'inputnode.bval_file')])
282+
])
283+
284+
else:
285+
ref_file = dwi_file
286+
287+
metadata = layout.get_metadata(ref_file)
288+
289+
dwi_preproc_wf = init_dwi_preproc_wf(
290+
layout=layout,
291+
output_dir=output_dir,
292+
subject_id=subject_id,
293+
dwi_file=dwi_file,
294+
metadata=metadata,
295+
b0_thresh=b0_thresh,
296+
output_resolution=output_resolution,
297+
bet_dwi=bet_dwi,
298+
bet_mag=bet_mag,
299+
omp_nthreads=omp_nthreads,
300+
acqp_file=acqp_file,
301+
ignore=ignore,
302+
synb0_dir=synb0_dir
303+
)
304+
305+
dwi_preproc_wf.base_dir = os.path.join(
306+
os.path.abspath(work_dir), subject_id
307+
)
308+
309+
inputspec = dwi_preproc_wf.get_node('inputnode')
310+
inputspec.inputs.subject_id = subject_id
311+
inputspec.inputs.dwi_file = dwi_file
312+
inputspec.inputs.dwi_meta = metadata
313+
inputspec.inputs.bvec_file = layout.get_bvec(dwi_file)
314+
inputspec.inputs.bval_file = layout.get_bval(dwi_file)
315+
inputspec.inputs.out_dir = os.path.abspath(output_dir)
316+
234317
entities = layout.parse_file_entities(dwi_file)
235318
if 'session' in entities:
236319
session_id = entities['session']
237320
else:
238321
session_id = None
239-
metadata = layout.get_metadata(dwi_file)
240-
241-
dwi_preproc_wf = init_dwi_preproc_wf(
242-
layout=layout,
243-
output_dir=output_dir,
244-
subject_id=subject_id,
245-
dwi_file=dwi_file,
246-
metadata=metadata,
247-
b0_thresh=b0_thresh,
248-
output_resolution=output_resolution,
249-
bet_dwi=bet_dwi,
250-
bet_mag=bet_mag,
251-
omp_nthreads=omp_nthreads,
252-
acqp_file=acqp_file,
253-
ignore=ignore,
254-
synb0_dir=synb0_dir
255-
)
256322

257323
datasink_wf = init_dwi_derivatives_wf(
258324
subject_id=subject_id,
259325
session_id=session_id,
260326
output_folder=output_dir
261327
)
262328

263-
dwi_preproc_wf.base_dir = os.path.join(
264-
os.path.abspath(work_dir), subject_id
265-
)
266-
267-
inputspec = dwi_preproc_wf.get_node('inputnode')
268-
inputspec.inputs.subject_id = subject_id
269-
inputspec.inputs.dwi_file = dwi_file
270-
inputspec.inputs.dwi_meta = metadata
271-
inputspec.inputs.bvec_file = layout.get_bvec(dwi_file)
272-
inputspec.inputs.bval_file = layout.get_bval(dwi_file)
273-
inputspec.inputs.out_dir = os.path.abspath(output_dir)
274-
275329
ds_inputspec = datasink_wf.get_node('inputnode')
276330
ds_inputspec.inputs.subject_id = subject_id
277331
ds_inputspec.inputs.session_id = session_id
@@ -312,23 +366,3 @@ def init_single_subject_wf(
312366
subject_wf.add_nodes([full_wf])
313367

314368
return subject_wf
315-
316-
317-
def group_dwis(dwi_files, sessions, concat_dwis):
318-
319-
all_dwis = []
320-
321-
if sessions:
322-
session_dwi_groups = []
323-
for session in sessions:
324-
session_dwi_files = [img for img in dwi_files if 'ses-{}'.format(session) in img]
325-
for f in session_dwi_files:
326-
if any(acq in f for acq in concat_dwis):
327-
session_dwi_groups.append(f)
328-
else:
329-
all_dwis.append(f)
330-
all_dwis.append(session_dwi_groups)
331-
else:
332-
all_dwis.append(f)
333-
334-
return all_dwis

dmriprep/workflows/dwi/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
77
88
.. automodule:: dmriprep.workflows.dwi.base
9+
.. automodule:: dmriprep.workflows.dwi.util
910
.. automodule:: dmriprep.workflows.dwi.artifacts
1011
.. automodule:: dmriprep.workflows.dwi.eddy
1112
.. automodule:: dmriprep.workflows.dwi.tensor
@@ -14,13 +15,15 @@
1415
"""
1516

1617
from .base import init_dwi_preproc_wf
18+
from .util import init_dwi_concat_wf
1719
from .artifacts import init_dwi_artifacts_wf
1820
from .eddy import init_dwi_eddy_wf
1921
from .tensor import init_dwi_tensor_wf
2022
from .outputs import init_dwi_derivatives_wf
2123

2224
__all__ = [
2325
'init_dwi_preproc_wf',
26+
'init_dwi_concat_wf',
2427
'init_dwi_artifacts_wf',
2528
'init_dwi_eddy_wf',
2629
'init_dwi_tensor_wf',

0 commit comments

Comments
 (0)