def correct_bias_field(in_file: Path, out_file: Path): """ Perform DWI B1 field inhomogenity correction. Parameters ---------- in_file : Path Path to SD-corrected DWI series out_file : Path Path to output B1 bias-field corrected DWI series """ ants_flag = ( subprocess.check_output(["N4BiasFieldCorrection", "--version"]) .decode("utf-8") .lower()[:12] ) == "ants version" bias_correct = mrt.DWIBiasCorrect() if ants_flag: algorithm = "ANTs" bias_correct.inputs.use_ants = True else: algorithm = "FSL" bias_correct.inputs.use_fsl = True bias_correct.inputs.in_file = in_file bias_correct.inputs.out_file = out_file return bias_correct, algorithm
def bias_correct(in_file: str, out_file: str): bs_correction = mrt.DWIBiasCorrect() bs_correction.inputs.in_file = in_file bs_correction.inputs.use_fsl = True bs_correction.inputs.out_file = out_file print(bs_correction.cmdline) bs_correction.run() return out_file
def build_core_nodes(self): """Build and connect the core nodes of the pipeline.""" import nipype.interfaces.ants as ants import nipype.interfaces.fsl as fsl import nipype.interfaces.mrtrix3 as mrtrix3 import nipype.interfaces.utility as nutil import nipype.interfaces.utility as niu import nipype.pipeline.engine as npe from nipype.interfaces.fsl.epi import Eddy from clinica.utils.dwi import ( compute_average_b0, generate_acq_file, generate_index_file, ) from .dwi_preprocessing_using_phasediff_fmap_utils import ( get_grad_fsl, init_input_node, print_end_pipeline, ) from .dwi_preprocessing_using_phasediff_fmap_workflows import ( prepare_phasediff_fmap, ) # Step 0: Initialization # ====================== # Initialize input parameters and print begin message init_node = npe.Node( interface=nutil.Function( input_names=self.get_input_fields(), output_names=[ "image_id", "dwi", "bvec", "bval", "total_readout_time", "phase_encoding_direction", "fmap_magnitude", "fmap_phasediff", "delta_echo_time", ], function=init_input_node, ), name="0-InitNode", ) # Generate (bvec, bval) tuple for MRtrix interfaces get_grad_fsl = npe.Node( nutil.Function( input_names=["bval", "bvec"], output_names=["grad_fsl"], function=get_grad_fsl, ), name="0-GetFslGrad", ) # Generate <image_id>_acq.txt for eddy gen_acq_txt = npe.Node( nutil.Function( input_names=[ "in_dwi", "fsl_phase_encoding_direction", "total_readout_time", "image_id", ], output_names=["out_acq"], function=generate_acq_file, ), name="0-GenerateAcqFile", ) # Generate <image_id>_index.txt for eddy gen_index_txt = npe.Node( nutil.Function( input_names=["in_bval", "low_bval", "image_id"], output_names=["out_index"], function=generate_index_file, ), name="0-GenerateIndexFile", ) gen_index_txt.inputs.low_bval = self.parameters["low_bval"] # Step 1: Computation of the reference b0 (i.e. average b0 but with EPI distortions) # ======================================= # Compute whole brain mask pre_mask_b0 = npe.Node(mrtrix3.BrainMask(), name="1a-PreMaskB0") pre_mask_b0.inputs.out_file = ( "brainmask.nii.gz" # On default, .mif file is generated ) # Run eddy without calibrated fmap pre_eddy = npe.Node(name="1b-PreEddy", interface=Eddy()) pre_eddy.inputs.repol = True pre_eddy.inputs.use_cuda = self.parameters["use_cuda"] pre_eddy.inputs.initrand = self.parameters["initrand"] # Compute the reference b0 compute_ref_b0 = npe.Node( niu.Function( input_names=["in_dwi", "in_bval"], output_names=["out_b0_average"], function=compute_average_b0, ), name="1c-ComputeReferenceB0", ) compute_ref_b0.inputs.low_bval = self.parameters["low_bval"] # Compute brain mask from reference b0 mask_ref_b0 = npe.Node(fsl.BET(mask=True, robust=True), name="1d-MaskReferenceB0") # Step 2: Calibrate and register FMap # =================================== # Bias field correction of the magnitude image bias_mag_fmap = npe.Node(ants.N4BiasFieldCorrection(dimension=3), name="2a-N4MagnitudeFmap") # Brain extraction of the magnitude image bet_mag_fmap = npe.Node(fsl.BET(frac=0.4, mask=True), name="2b-BetN4MagnitudeFmap") # Calibrate FMap calibrate_fmap = prepare_phasediff_fmap(name="2c-CalibrateFMap") # Register the BET magnitude fmap onto the BET b0 bet_mag_fmap2b0 = npe.Node(interface=fsl.FLIRT(), name="2d-RegistrationBetMagToB0") bet_mag_fmap2b0.inputs.dof = 6 bet_mag_fmap2b0.inputs.output_type = "NIFTI_GZ" # Apply the transformation on the calibrated fmap fmap2b0 = npe.Node(interface=fsl.ApplyXFM(), name="2e-1-FMapToB0") fmap2b0.inputs.output_type = "NIFTI_GZ" # Apply the transformation on the magnitude image mag_fmap2b0 = fmap2b0.clone("2e-2-MagFMapToB0") # Smooth the registered (calibrated) fmap smoothing = npe.Node(interface=fsl.maths.IsotropicSmooth(), name="2f-Smoothing") smoothing.inputs.sigma = 4.0 # Step 3: Run FSL eddy # ==================== eddy = pre_eddy.clone("3-Eddy") # Step 4: Bias correction # ======================= # Use implementation detailed in (Jeurissen et al., 2014) bias = npe.Node(mrtrix3.DWIBiasCorrect(use_ants=True), name="4-RemoveBias") # Step 5: Final brainmask # ======================= # Compute average b0 on corrected dataset (for brain mask extraction) compute_avg_b0 = compute_ref_b0.clone("5a-ComputeB0Average") # Compute b0 mask on corrected avg b0 mask_avg_b0 = mask_ref_b0.clone("5b-MaskB0") # Print end message print_end_message = npe.Node( interface=nutil.Function(input_names=["image_id", "final_file"], function=print_end_pipeline), name="99-WriteEndMessage", ) # Connection # ========== # fmt: off self.connect([ # Step 0: Initialization # ====================== # Initialize input parameters and print begin message (self.input_node, init_node, [("dwi", "dwi"), ("bvec", "bvec"), ("bval", "bval"), ("dwi_json", "dwi_json"), ("fmap_magnitude", "fmap_magnitude"), ("fmap_phasediff", "fmap_phasediff"), ("fmap_phasediff_json", "fmap_phasediff_json")]), # Generate (bvec, bval) tuple for MRtrix interfaces (init_node, get_grad_fsl, [("bval", "bval"), ("bvec", "bvec")]), # Generate <image_id>_acq.txt for eddy (init_node, gen_acq_txt, [("dwi", "in_dwi"), ("total_readout_time", "total_readout_time"), ("phase_encoding_direction", "fsl_phase_encoding_direction"), ("image_id", "image_id")]), # Generate <image_id>_index.txt for eddy (init_node, gen_index_txt, [("bval", "in_bval"), ("image_id", "image_id")]), # Step 1: Computation of the reference b0 (i.e. average b0 but with EPI distortions) # ======================================= # Compute whole brain mask (get_grad_fsl, pre_mask_b0, [("grad_fsl", "grad_fsl")]), (init_node, pre_mask_b0, [("dwi", "in_file")]), # Run eddy without calibrated fmap (init_node, pre_eddy, [("dwi", "in_file"), ("bval", "in_bval"), ("bvec", "in_bvec"), ("image_id", "out_base")]), (gen_acq_txt, pre_eddy, [("out_acq", "in_acqp")]), (gen_index_txt, pre_eddy, [("out_index", "in_index")]), (pre_mask_b0, pre_eddy, [("out_file", "in_mask")]), # Compute the reference b0 (init_node, compute_ref_b0, [("bval", "in_bval")]), (pre_eddy, compute_ref_b0, [("out_corrected", "in_dwi")]), # Compute brain mask from reference b0 (compute_ref_b0, mask_ref_b0, [("out_b0_average", "in_file")]), # Step 2: Calibrate and register FMap # =================================== # Bias field correction of the magnitude image (init_node, bias_mag_fmap, [("fmap_magnitude", "input_image")]), # Brain extraction of the magnitude image (bias_mag_fmap, bet_mag_fmap, [("output_image", "in_file")]), # Calibration of the FMap (bet_mag_fmap, calibrate_fmap, [("mask_file", "input_node.fmap_mask"), ("out_file", "input_node.fmap_magnitude")]), (init_node, calibrate_fmap, [("fmap_phasediff", "input_node.fmap_phasediff"), ("delta_echo_time", "input_node.delta_echo_time")]), # Register the BET magnitude fmap onto the BET b0 (bet_mag_fmap, bet_mag_fmap2b0, [("out_file", "in_file")]), (mask_ref_b0, bet_mag_fmap2b0, [("out_file", "reference")]), # Apply the transformation on the magnitude image (bet_mag_fmap2b0, mag_fmap2b0, [("out_matrix_file", "in_matrix_file")]), (bias_mag_fmap, mag_fmap2b0, [("output_image", "in_file")]), (mask_ref_b0, mag_fmap2b0, [("out_file", "reference")]), # Apply the transformation on the calibrated fmap (bet_mag_fmap2b0, fmap2b0, [("out_matrix_file", "in_matrix_file")] ), (calibrate_fmap, fmap2b0, [("output_node.calibrated_fmap", "in_file")]), (mask_ref_b0, fmap2b0, [("out_file", "reference")]), # # Smooth the registered (calibrated) fmap (fmap2b0, smoothing, [("out_file", "in_file")]), # Step 3: Run FSL eddy # ==================== (init_node, eddy, [("dwi", "in_file"), ("bval", "in_bval"), ("bvec", "in_bvec"), ("image_id", "out_base")]), (gen_acq_txt, eddy, [("out_acq", "in_acqp")]), (gen_index_txt, eddy, [("out_index", "in_index")]), (smoothing, eddy, [("out_file", "field")]), (pre_mask_b0, eddy, [("out_file", "in_mask")]), # Step 4: Bias correction # ======================= (init_node, bias, [("bval", "in_bval")]), (eddy, bias, [("out_rotated_bvecs", "in_bvec"), ("out_corrected", "in_file")]), # Step 5: Final brainmask # ======================= # Compute average b0 on corrected dataset (for brain mask extraction) (init_node, compute_avg_b0, [("bval", "in_bval")]), (bias, compute_avg_b0, [("out_file", "in_dwi")]), # Compute b0 mask on corrected avg b0 (compute_avg_b0, mask_avg_b0, [("out_b0_average", "in_file")]), # Print end message (init_node, print_end_message, [("image_id", "image_id")]), (mask_avg_b0, print_end_message, [("mask_file", "final_file")]), # Output node (init_node, self.output_node, [("bval", "preproc_bval")]), (eddy, self.output_node, [("out_rotated_bvecs", "preproc_bvec")]), (bias, self.output_node, [("out_file", "preproc_dwi")]), (mask_avg_b0, self.output_node, [("mask_file", "b0_mask")]), (bet_mag_fmap2b0, self.output_node, [("out_file", "magnitude_on_b0")]), (fmap2b0, self.output_node, [("out_file", "calibrated_fmap_on_b0") ]), (smoothing, self.output_node, [("out_file", "smoothed_fmap_on_b0") ]), ])
def preprocess_dwi_data(self, data, index, acqp, atlas2use, ResponseSD_algorithm='tournier', fod_algorithm='csd', tract_algorithm='iFOD2', streamlines_number='10M'): ''' preprocessing of dwi data and connectome extraction Parameters ---------- subjects_dir = path to the subjects' folders data: tuple | a tuple having the path to dwi, bvecs and bvals files. It is obtained using the function grab_data() index: str | Name of text file specifying the relationship between the images in --imain and the information in --acqp and --topup. E.g. index.txt acqp: str | Name of text file with information about the acquisition of the images in --imain atlas2use: str | The input node parcellation image ResponseSD_algorithm (optional): str | Select the algorithm to be used to complete the script operation; Options are: dhollander, fa, manual, msmt_5tt, tax, tournier (Default is 'tournier') fod_algorithm (optional): str | The algorithm to use for FOD estimation. (options are: csd,msmt_csd) (Default is 'csd') tract_algorithm (optional): str | specify the tractography algorithm to use. Valid choices are: FACT, iFOD1, iFOD2, Nulldist1, Nulldist2, SD_Stream, Seedtest, Tensor_Det, Tensor_Prob (Default is 'iFOD2') streamlines_number (optional): str | set the desired number of streamlines (Default is '10M') ''' if len(data[0]) != len(data[1]): raise ValueError( 'dwi datas do not have the same shape of bvec files') if len(data[0]) != len(data[2]): raise ValueError( 'dwi datas do not have the same shape of bval files') if len(data[1]) != len(data[2]): raise ValueError( 'bvec files do not have the same shape of bvec files') for subj in range(len(data[0])): print('Extracting B0 volume for subject', subj) self.roi = fsl.ExtractROI( in_file=data[0][subj], roi_file=os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_nodiff.nii.gz'), t_min=0, t_size=1) self.roi.run() print('Converting into .mif for subject', subj) self.mrconvert = mrt.MRConvert() self.mrconvert.inputs.in_file = data[0][subj] self.mrconvert.inputs.grad_fsl = (data[1][subj], data[2][subj]) self.mrconvert.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi.mif') self.mrconvert.run() print('Denoising data for subject', subj) self.denoise = mrt.DWIDenoise() self.denoise.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi.mif') self.denoise.inputs.noise = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_noise.mif') self.denoise.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.mif') self.denoise.run() self.denoise_convert = mrt.MRConvert() self.denoise_convert.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.mif') self.denoise_convert.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.nii.gz') self.denoise_convert.run() print('Skull stripping for subject', subj) self.mybet = fsl.BET() self.mybet.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_nodiff.nii.gz') self.mybet.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain.nii.gz') self.mybet.inputs.frac = 0.1 self.mybet.inputs.robust = True self.mybet.inputs.mask = True self.mybet.run() print('Running Eddy for subject', subj) self.eddy = Eddy() self.eddy.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.nii.gz') self.eddy.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.eddy.inputs.in_acqp = acqp self.eddy.inputs.in_bvec = data[1][subj] self.eddy.inputs.in_bval = data[2][subj] self.eddy.inputs.out_base = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.nii.gz') self.eddy.run() print('Running Bias Correction for subject', subj) self.bias_correct = mrt.DWIBiasCorrect() self.bias_correct.inputs.use_ants = True self.bias_correct.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.nii.gz') self.bias_correct.inputs.grad_fsl = (os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.eddy_rotated_bvecs.bvec'), data[2][subj]) self.bias_correct.inputs.bias = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_bias.mif') self.bias_correct.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy_unbiased.mif') self.bias_correct.run() print('Calculating Response function for subject', subj) self.resp = mrt.ResponseSD() self.resp.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy_unbiased.mif') self.resp.inputs.algorithm = ResponseSD_algorithm self.resp.inputs.grad_fsl = (os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.eddy_rotated_bvecs.bvec'), data[2][subj]) self.resp.inputs.wm_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_response.txt') self.resp.run() print('Estimating FOD for subject', subj) self.fod = mrt.EstimateFOD() self.fod.inputs.algorithm = fod_algorithm self.fod.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy_unbiased.mif') self.fod.inputs.wm_txt = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_response.txt') self.fod.inputs.mask_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.fod.inputs.grad_fsl = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_response.txt') self.fod.run() print('Extracting whole brain tract for subject', subj) self.tk = mrt.Tractography() self.tk.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + 'fods.mif') self.tk.inputs.roi_mask = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.tk.inputs.algorithm = tract_algorithm self.tk.inputs.seed_image = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.tk.inputs.select = streamlines_number self.tk.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_whole_brain_' + streamlines_number + '.tck') self.tk.run() print('Extracting connectome for subject', subj) self.mat = mrt.BuildConnectome() self.mat.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_whole_brain_' + streamlines_number + '.tck') self.mat.inputs.in_parc = atlas2use self.mat.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_connectome.csv') self.mat.run()
name='io_data_grabber') io_data_grabber.inputs.sort_filelist = True io_data_grabber.inputs.template = "/Users/bsms9gep/data/*.nii" #Wraps the executable command ``mrconvert``. mrtrix3_mrconvert = pe.Node(interface=mrtrix3.MRConvert(), name='mrtrix3_mrconvert') mrtrix3_mrconvert.inputs.grad_fsl = ("/Users/bsms9gep/data/bvecs", "/Users/bsms9gep/data/bvals") #Wraps the executable command ``dwi2mask``. mrtrix3_brain_mask = pe.Node(interface=mrtrix3.BrainMask(), name='mrtrix3_brain_mask') #Wraps the executable command ``dwibiascorrect``. mrtrix3_dwibias_correct = pe.Node(interface=mrtrix3.DWIBiasCorrect(), name='mrtrix3_dwibias_correct') mrtrix3_dwibias_correct.inputs.out_file = 'dwi_unbiased.mif' #Wraps the executable command ``dwi2response``. mrtrix3_response_sd = pe.Node(interface=mrtrix3.ResponseSD(), name='mrtrix3_response_sd') mrtrix3_response_sd.inputs.algorithm = 'dhollander' mrtrix3_response_sd.inputs.gm_file = 'gm.txt' mrtrix3_response_sd.inputs.csf_file = 'csf.txt' mrtrix3_response_sd.inputs.max_sh = (8, 8, 8) #Wraps the executable command ``dwi2fod``. mrtrix3_estimate_fod = pe.Node(interface=mrtrix3.EstimateFOD(), name='mrtrix3_estimate_fod') mrtrix3_estimate_fod.inputs.algorithm = 'msmt_csd'
def build_core_nodes(self): """Build and connect the core nodes of the pipeline.""" import nipype.interfaces.fsl as fsl import nipype.interfaces.mrtrix3 as mrtrix3 import nipype.interfaces.utility as nutil import nipype.pipeline.engine as npe from clinica.utils.dwi import compute_average_b0 from .dwi_preprocessing_using_t1_utils import ( init_input_node, prepare_reference_b0, print_end_pipeline, ) from .dwi_preprocessing_using_t1_workflows import ( eddy_fsl_pipeline, epi_pipeline, ) # Nodes creation # ============== # Initialize input parameters and print begin message init_node = npe.Node( interface=nutil.Function( input_names=self.get_input_fields(), output_names=[ "image_id", "t1w", "dwi", "bvec", "bval", "total_readout_time", "phase_encoding_direction", ], function=init_input_node, ), name="0-InitNode", ) # Prepare b0 image for further corrections prepare_b0 = npe.Node( name="PrepareB0", interface=nutil.Function( input_names=[ "in_dwi", "in_bval", "in_bvec", "low_bval", "working_directory", ], output_names=[ "out_reference_b0", "out_b0_dwi_merge", "out_updated_bval", "out_updated_bvec", ], function=prepare_reference_b0, ), ) prepare_b0.inputs.low_bval = self.parameters["low_bval"] prepare_b0.inputs.working_directory = self.base_dir # Mask b0 for computations purposes mask_b0_pre = npe.Node(fsl.BET(frac=0.3, mask=True, robust=True), name="PreMaskB0") # Head-motion correction + Eddy-currents correction eddy_fsl = eddy_fsl_pipeline( low_bval=self.parameters["low_bval"], use_cuda=self.parameters["use_cuda"], initrand=self.parameters["initrand"], ) # Susceptibility distortion correction using T1w image sdc = epi_pipeline(name="SusceptibilityDistortionCorrection") # Remove bias correction from (Jeurissen et al., 2014) bias = npe.Node(mrtrix3.DWIBiasCorrect(use_ants=True), name="RemoveBias") # Compute b0 mask on corrected avg b0 compute_avg_b0 = npe.Node( nutil.Function( input_names=["in_dwi", "in_bval"], output_names=["out_b0_average"], function=compute_average_b0, ), name="ComputeB0Average", ) compute_avg_b0.inputs.low_bval = self.parameters["low_bval"] # Compute brain mask from reference b0 mask_avg_b0 = npe.Node(fsl.BET(mask=True, robust=True), name="MaskB0") # Print end message print_end_message = npe.Node( interface=nutil.Function(input_names=["image_id", "final_file"], function=print_end_pipeline), name="WriteEndMessage", ) # Connection # ========== # fmt: off self.connect([ # Initialize input parameters and print begin message (self.input_node, init_node, [("t1w", "t1w"), ("dwi", "dwi"), ("bvec", "bvec"), ("bval", "bval"), ("dwi_json", "dwi_json")]), # Preliminary step (possible computation of a mean b0): (init_node, prepare_b0, [("dwi", "in_dwi"), ("bval", "in_bval"), ("bvec", "in_bvec")]), # Mask b0 before corrections (prepare_b0, mask_b0_pre, [("out_reference_b0", "in_file")]), # Head-motion correction + eddy current correction (init_node, eddy_fsl, [("total_readout_time", "inputnode.total_readout_time"), ("phase_encoding_direction", "inputnode.phase_encoding_direction")]), (prepare_b0, eddy_fsl, [("out_b0_dwi_merge", "inputnode.in_file"), ("out_updated_bval", "inputnode.in_bval"), ("out_updated_bvec", "inputnode.in_bvec"), ("out_reference_b0", "inputnode.ref_b0")]), (mask_b0_pre, eddy_fsl, [("mask_file", "inputnode.in_mask")]), # Magnetic susceptibility correction (init_node, sdc, [("t1w", "inputnode.T1")]), (eddy_fsl, sdc, [("outputnode.out_corrected", "inputnode.DWI")]), (eddy_fsl, sdc, [("outputnode.out_rotated_bvecs", "inputnode.bvec") ]), # Bias correction (prepare_b0, bias, [("out_updated_bval", "in_bval")]), (sdc, bias, [("outputnode.DWIs_epicorrected", "in_file"), ("outputnode.out_bvec", "in_bvec")]), # Compute average b0 on corrected dataset (for brain mask extraction) (prepare_b0, compute_avg_b0, [("out_updated_bval", "in_bval")]), (bias, compute_avg_b0, [("out_file", "in_dwi")]), # Compute b0 mask on corrected avg b0 (compute_avg_b0, mask_avg_b0, [("out_b0_average", "in_file")]), # Print end message (init_node, print_end_message, [("image_id", "image_id")]), (mask_avg_b0, print_end_message, [("mask_file", "final_file")]), # Output node (bias, self.output_node, [("out_file", "preproc_dwi")]), (sdc, self.output_node, [("outputnode.out_bvec", "preproc_bvec")]), (prepare_b0, self.output_node, [("out_updated_bval", "preproc_bval")]), (mask_avg_b0, self.output_node, [("mask_file", "b0_mask")]), ])