4
4
import os
5
5
import sys
6
6
import warnings
7
+ from multiprocessing import cpu_count
7
8
8
9
import click
9
10
from bids import BIDSLayout
11
+ from nipype import config as ncfg
10
12
11
13
from .utils .bids import collect_participants
12
14
from .workflows .base import init_dmriprep_wf
16
18
warnings .filterwarnings ('ignore' , message = 'numpy.dtype size changed' )
17
19
warnings .filterwarnings ('ignore' , message = 'numpy.ufunc size changed' )
18
20
21
+
19
22
@click .command ()
20
23
# arguments as specified by BIDS-Apps
21
24
@click .argument ('bids_dir' , type = click .Path (exists = True , file_okay = False ))
22
25
@click .argument (
23
26
'output_dir' , type = click .Path (exists = True , file_okay = False , writable = True )
24
27
)
25
28
@click .argument (
26
- 'analysis_level' , default = 'participant' , type = click .Choice (['participant' , 'group' ])
29
+ 'analysis_level' ,
30
+ default = 'participant' ,
31
+ type = click .Choice (['participant' , 'group' ])
27
32
)
28
33
# optional arguments
29
34
# options for filtering BIDS queries
66
71
default = 5 ,
67
72
show_default = True ,
68
73
help = 'Threshold for b0 value' ,
69
- type = click .IntRange (min = 0 , max = 10 ),
74
+ type = click .IntRange (min = 0 , max = 10 )
70
75
)
71
76
@click .option (
72
77
'--output_resolution' ,
73
78
help = 'The isotropic voxel size in mm the data will be resampled to before eddy.' ,
74
79
type = float ,
75
80
multiple = True
76
81
)
77
- # specific options for eddy
78
- @click .option (
79
- '--nthreads' ,
80
- default = 1 ,
81
- show_default = True ,
82
- help = 'Maximum number of threads across all processes' ,
83
- type = int ,
84
- )
85
- @click .option (
86
- '--omp_nthreads' ,
87
- default = 1 ,
88
- show_default = True ,
89
- help = 'Maximum number of threads per process' ,
90
- type = int ,
91
- )
92
- @click .option (
93
- '--eddy_niter' ,
94
- default = 5 ,
95
- show_default = True ,
96
- help = 'Fixed number of eddy iterations. See '
97
- 'https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/eddy/UsersGuide'
98
- '#A--niter' ,
99
- type = int ,
100
- )
101
82
@click .option (
102
83
'--bet_dwi' ,
103
84
default = 0.3 ,
104
85
show_default = True ,
105
86
help = 'Fractional intensity threshold for BET on the DWI. '
106
87
'A higher value will be more strict; it will cut off more '
107
88
'around what it analyzes the brain to be.' ,
108
- type = click .FloatRange (min = 0 , max = 1 ),
89
+ type = click .FloatRange (min = 0 , max = 1 )
109
90
)
110
91
@click .option (
111
92
'--bet_mag' ,
114
95
help = 'Fractional intensity threshold for BET on the magnitude. '
115
96
'A higher value will be more strict; it will cut off more '
116
97
'around what it analyzes the brain to be.' ,
117
- type = click .FloatRange (min = 0 , max = 1 ),
98
+ type = click .FloatRange (min = 0 , max = 1 )
99
+ )
100
+ # specific options for eddy
101
+ @click .option (
102
+ '--nthreads' ,
103
+ default = 1 ,
104
+ show_default = True ,
105
+ help = 'Maximum number of threads across all processes' ,
106
+ type = int
107
+ )
108
+ @click .option (
109
+ '--omp_nthreads' ,
110
+ default = 1 ,
111
+ show_default = True ,
112
+ help = 'Maximum number of threads per process' ,
113
+ type = int
118
114
)
119
115
@click .option (
120
116
'--acqp_file' ,
121
117
default = None ,
122
118
help = 'If you want to pass in an acqp file for topup/eddy instead of'
123
119
'generating it from the json by default.' ,
124
- type = click .Path (exists = True , dir_okay = False ),
120
+ type = click .Path (exists = True , dir_okay = False )
125
121
)
126
122
# workflow configuration
127
123
@click .option (
128
124
'--ignore' ,
129
125
'-i' ,
130
126
help = 'Specify which node(s) to skip during the preprocessing of the dwi.' ,
131
127
type = click .Choice (['denoising' , 'unringing' , 'fieldmaps' ]),
132
- multiple = True ,
128
+ multiple = True
133
129
)
134
130
@click .option (
135
131
'--work_dir' ,
136
132
'-w' ,
137
133
help = 'working directory' ,
138
- type = click .Path (exists = True , file_okay = False , writable = True ),
134
+ type = click .Path (exists = True , file_okay = False , writable = True )
139
135
)
140
136
@click .option (
141
137
'--synb0_dir' ,
142
138
default = None ,
143
139
help = 'If you want to use Synb0-DISCO for preprocessing.' ,
144
- type = click .Path (exists = True , file_okay = False ),
140
+ type = click .Path (exists = True , file_okay = False )
141
+ )
142
+ @click .option (
143
+ '--write_graph' ,
144
+ default = False ,
145
+ help = 'Write out nipype workflow graph.'
145
146
)
146
147
def main (
147
- participant_label ,
148
- session_label ,
149
148
bids_dir ,
150
149
output_dir ,
151
150
analysis_level ,
152
151
skip_bids_validation ,
153
- work_dir ,
154
- ignore ,
152
+ participant_label ,
153
+ session_label ,
155
154
concat_dwis ,
156
155
b0_thresh ,
157
156
output_resolution ,
158
157
bet_dwi ,
159
158
bet_mag ,
160
159
nthreads ,
161
160
omp_nthreads ,
162
- eddy_niter ,
161
+ acqp_file ,
162
+ ignore ,
163
+ work_dir ,
163
164
synb0_dir ,
164
- acqp_file
165
+ write_graph
165
166
):
166
167
"""
167
168
BIDS_DIR: The directory with the input dataset formatted according to the
@@ -188,7 +189,6 @@ def main(
188
189
189
190
if not skip_bids_validation :
190
191
from .utils .bids import validate_input_dir
191
-
192
192
validate_input_dir (bids_dir , all_subjects , subject_list )
193
193
194
194
if not work_dir :
@@ -197,27 +197,61 @@ def main(
197
197
if len (output_resolution ) == 1 :
198
198
output_resolution = output_resolution * 3
199
199
200
+ log_dir = os .path .join (output_dir , 'dmriprep' , 'logs' )
201
+
202
+ plugin_settings = {
203
+ 'plugin' : 'MultiProc' ,
204
+ 'plugin_args' : {
205
+ 'raise_insufficient' : False ,
206
+ 'maxtasksperchild' : 1 ,
207
+ 'n_procs' : nthreads
208
+ }
209
+ }
210
+
211
+ if omp_nthreads == 0 :
212
+ omp_nthreads = min (nthreads - 1 if nthreads > 1 else cpu_count (), 8 )
213
+
214
+ ncfg .update_config ({
215
+ 'logging' : {
216
+ 'log_directory' : log_dir ,
217
+ 'log_to_file' : True
218
+ },
219
+ 'execution' : {
220
+ 'crashdump_dir' : log_dir ,
221
+ 'crashfile_format' : 'txt' ,
222
+ 'remove_unnecessary_outputs' : False ,
223
+ 'keep_inputs' : True ,
224
+ 'get_linked_libs' : False ,
225
+ 'stop_on_first_crash' : True
226
+ },
227
+ 'monitoring' : {
228
+ 'enabled' : True ,
229
+ 'sample_frequency' : '0.5' ,
230
+ 'summary_append' : True
231
+ }
232
+ })
233
+
200
234
wf = init_dmriprep_wf (
201
- subject_list = subject_list ,
202
- session_list = session_label ,
203
235
layout = layout ,
204
236
output_dir = output_dir ,
205
- work_dir = work_dir ,
206
- ignore = list (ignore ),
237
+ subject_list = subject_list ,
238
+ session_list = list (session_label ),
207
239
concat_dwis = list (concat_dwis ),
208
240
b0_thresh = b0_thresh ,
209
241
output_resolution = output_resolution ,
210
242
bet_dwi = bet_dwi ,
211
243
bet_mag = bet_mag ,
212
- nthreads = nthreads ,
213
244
omp_nthreads = omp_nthreads ,
245
+ acqp_file = acqp_file ,
246
+ ignore = list (ignore ),
247
+ work_dir = work_dir ,
214
248
synb0_dir = synb0_dir
215
249
)
216
- wf . write_graph ()
217
- wf . config [ 'execution' ][ 'remove_unnecessary_outputs' ] = False
218
- wf .config [ 'execution' ][ 'keep_inputs' ] = True
219
- wf . config [ 'execution' ][ 'crashfile_format' ] = 'txt'
220
- wf .run ()
250
+
251
+ if write_graph :
252
+ wf .write_graph ( graph2use = 'colored' , format = 'svg' , simple_form = True )
253
+
254
+ wf .run (** plugin_settings )
221
255
222
256
return 0
223
257
0 commit comments