def run_topup(self): topup = fsl.TOPUP() topup.inputs.in_file = self.b0_file topup.inputs.encoding_file = self.acq_file topup.inputs.out_base = self.topup_out # The following doesn't seem to help. I guess topup isn't parallelized. #topup.inputs.environ = {'FSLPARALLEL':'condor', 'OMP_NUM_THREADS':'12'} res = topup.run() self.b0_unwarped = res.outputs.out_corrected self.fieldcoef = res.outputs.out_fieldcoef self.movpar = res.outputs.out_movpar
def func_calc_disco_warp(): ''' Method to calculate and apply susceptibility induced distortion warps to a fresh functional image used topup and applytopup inputs inputnode.func inputnode.se_image inputnode.se_invpol inputnode.encoding_file outputnode outputnode.out_enc_file # encoding directions file output for applytopup outputnode.movpar # movpar.txt output file outputnode.fieldcoef # file containing the field coefficients ''' datain = '/scr/sambesi1/workspace/Projects/GluREST/functional/datain.txt' #define worflow flow = Workflow('func_distortion_correction') inputnode = Node( util.IdentityInterface(fields=['func', 'func_se', 'func_se_inv']), name='inputnode') outputnode = Node(util.IdentityInterface(fields=[ 'enc_file ', 'topup_movpar', 'topup_fieldcoef', 'topup_field', 'func_disco' ]), name='outputnode') # define nodes list_blips = Node(util.Merge(2), name='blips_list') make_blips = Node(fsl.Merge(), name='blips_merged') make_blips.inputs.dimension = 't' make_blips.inputs.output_type = 'NIFTI_GZ' topup = Node(interface=fsl.TOPUP(), name='calc_topup') topup.inputs.encoding_file = datain topup.inputs.output_type = "NIFTI_GZ" apply = Node(interface=fsl.ApplyTOPUP(), name='apply_topup') apply.inputs.in_index = [1] apply.inputs.encoding_file = datain apply.inputs.method = 'jac' apply.inputs.output_type = "NIFTI_GZ" # connect nodes flow.connect(inputnode, 'func_se', list_blips, 'in1') flow.connect(inputnode, 'func_se_inv', list_blips, 'in2') flow.connect(list_blips, 'out', make_blips, 'in_files') flow.connect(make_blips, 'merged_file', topup, 'in_file') flow.connect(inputnode, 'func', apply, 'in_files') flow.connect(topup, 'out_fieldcoef', apply, 'in_topup_fieldcoef') flow.connect(topup, 'out_movpar', apply, 'in_topup_movpar') flow.connect(topup, 'out_enc_file', outputnode, 'enc_file') flow.connect(topup, 'out_movpar', outputnode, 'topup_movpar') flow.connect(topup, 'out_fieldcoef', outputnode, 'topup_fieldcoef') flow.connect(topup, 'out_field', outputnode, 'topup_field') flow.connect(apply, 'out_corrected', outputnode, 'func_disco') return flow
def create_preproc_workflow(session): """ Defines simple functional preprocessing workflow, including motion correction, registration to distortion scans, and unwarping. Assumes recon-all has been performed on T1, and computes but does not apply registration to anatomy. """ #---Create workflow--- wf = Workflow(name='workflow', base_dir=session['working_dir']) #---EPI Realignment--- # Realign every TR in each functional run to the sbref image using mcflirt realign = MapNode(fsl.MCFLIRT(ref_file=session['sbref'], save_mats=True, save_plots=True), iterfield=['in_file'], name='realign') realign.inputs.in_file = session['epis'] wf.add_nodes([realign]) #---Registration to distortion scan--- # Register the sbref scan to the distortion scan with the same PE using flirt reg2dist = Node(fsl.FLIRT(in_file=session['sbref'], reference=session['distort_PE'], out_file='sbref_reg.nii.gz', out_matrix_file='sbref2dist.mat', dof=6), name='reg2distort') wf.add_nodes([reg2dist]) #---Distortion correction--- # Merge the two distortion scans for unwarping distort_scans = [session['distort_PE'], session['distort_revPE']] merge_dist = Node(fsl.Merge(in_files=distort_scans, dimension='t', merged_file='distortion_merged.nii.gz'), name='merge_distort') wf.add_nodes([merge_dist]) # Run topup to estimate warpfield and create unwarped distortion scans if '-' not in session['PE_dim']: PEs = np.repeat([session['PE_dim'], session['PE_dim'] + '-'], 3) else: PEs = np.repeat( [session['PE_dim'], session['PE_dim'].replace('-', '')], 3) unwarp_dist = Node(fsl.TOPUP(encoding_direction=list(PEs), readout_times=[1, 1, 1, 1, 1, 1], config='b02b0.cnf', fwhm=0), name='unwarp_distort') wf.connect(merge_dist, 'merged_file', unwarp_dist, 'in_file') # Unwarp sbref image in case it's useful unwarp_sbref = Node(fsl.ApplyTOPUP(in_index=[1], method='jac'), name='unwarp_sbref') wf.connect([(reg2dist, unwarp_sbref, [('out_file', 'in_files')]), (unwarp_dist, unwarp_sbref, [('out_enc_file', 'encoding_file'), ('out_fieldcoef', 'in_topup_fieldcoef'), ('out_movpar', 'in_topup_movpar')])]) #---Registration to anatomy--- # Create mean unwarped distortion scan mean_unwarped_dist = Node(fsl.MeanImage(dimension='T'), name='mean_unwarped_distort') wf.connect(unwarp_dist, 'out_corrected', mean_unwarped_dist, 'in_file') # Register mean unwarped distortion scan to anatomy using bbregister reg2anat = Node(fs.BBRegister( subject_id=session['Freesurfer_subject_name'], contrast_type='t2', init='fsl', out_reg_file='distort2anat_tkreg.dat', out_fsl_file='distort2anat_flirt.mat'), name='reg2anat') wf.connect(mean_unwarped_dist, 'out_file', reg2anat, 'source_file') #---Combine and apply transforms to EPIs--- # Split EPI runs into 3D files split_epis = MapNode(fsl.Split(dimension='t'), iterfield=['in_file'], name='split_epis') split_epis.inputs.in_file = session['epis'] wf.add_nodes([split_epis]) # Combine the rigid transforms to be applied to each EPI volume concat_rigids = MapNode(fsl.ConvertXFM(concat_xfm=True), iterfield=['in_file'], nested=True, name='concat_rigids') wf.connect([(realign, concat_rigids, [('mat_file', 'in_file')]), (reg2dist, concat_rigids, [('out_matrix_file', 'in_file2')])]) # Apply rigid transforms and warpfield to each EPI volume correct_epis = MapNode(fsl.ApplyWarp(interp='spline', relwarp=True), iterfield=['in_file', 'ref_file', 'premat'], nested=True, name='correct_epis') get_warp = lambda warpfields: warpfields[0] wf.connect([(split_epis, correct_epis, [('out_files', 'in_file'), ('out_files', 'ref_file')]), (concat_rigids, correct_epis, [('out_file', 'premat')]), (unwarp_dist, correct_epis, [(('out_warps', get_warp), 'field_file')])]) # Merge processed files back into 4D nifti merge_epis = MapNode(fsl.Merge(dimension='t', merged_file='timeseries_corrected.nii.gz'), iterfield='in_files', name='merge_epis') wf.connect([(correct_epis, merge_epis, [('out_file', 'in_files')])]) #---Copy important files to main directory--- substitutions = [('_merge_epis%d/timeseries_corrected.nii.gz' % i, n) for i, n in enumerate(session['out_names'])] ds = Node(DataSink(base_directory=os.path.abspath(session['out']), substitutions=substitutions), name='outfiles') wf.connect(unwarp_dist, 'out_corrected', ds, '@unwarp_dist') wf.connect(mean_unwarped_dist, 'out_file', ds, '@mean_unwarped_dist') wf.connect(unwarp_sbref, 'out_corrected', ds, '@unwarp_sbref') wf.connect(reg2anat, 'out_reg_file', ds, '@reg2anat') wf.connect(merge_epis, 'merged_file', ds, '@merge_epis') return wf
def create_topup_workflow(analysis_info, name='topup'): ########################################################################### # NODES ########################################################################### input_node = pe.Node(IdentityInterface(fields=[ 'in_files', 'alt_files', 'conf_file', 'output_directory', 'echo_time', 'phase_encoding_direction', 'epi_factor' ]), name='inputspec') output_node = pe.Node( IdentityInterface(fields=['out_files', 'field_coefs']), name='outputspec') get_info = pe.MapNode(interface=Get_scaninfo, name='get_scaninfo', iterfield=['in_file']) dyns_min_1_node = pe.MapNode(interface=Dyns_min_1, name='dyns_min_1_node', iterfield=['dyns']) topup_scan_params_node = pe.Node(interface=Topup_scan_params, name='topup_scan_params') apply_scan_params_node = pe.MapNode(interface=Apply_scan_params, name='apply_scan_params', iterfield=['nr_trs']) PE_ref = pe.MapNode(fsl.ExtractROI(t_size=1), name='PE_ref', iterfield=['in_file', 't_min']) # hard-coded the timepoint for this node, no more need for alt_t. PE_alt = pe.MapNode(fsl.ExtractROI(t_min=0, t_size=1), name='PE_alt', iterfield=['in_file']) PE_comb = pe.MapNode(Merge(2), name='PE_list', iterfield=['in1', 'in2']) PE_merge = pe.MapNode(fsl.Merge(dimension='t'), name='PE_merged', iterfield=['in_files']) # implementing the contents of b02b0.cnf in the args, # while supplying an emtpy text file as a --config option # gets topup going on our server. topup_args = """--warpres=20,16,14,12,10,6,4,4,4 --subsamp=1,1,1,1,1,1,1,1,1 --fwhm=8,6,4,3,3,2,1,0,0 --miter=5,5,5,5,5,10,10,20,20 --lambda=0.005,0.001,0.0001,0.000015,0.000005,0.0000005,0.00000005,0.0000000005,0.00000000001 --ssqlambda=1 --regmod=bending_energy --estmov=1,1,1,1,1,0,0,0,0 --minmet=0,0,0,0,0,1,1,1,1 --splineorder=3 --numprec=double --interp=spline --scale=1 -v""" topup_node = pe.MapNode(fsl.TOPUP(args=topup_args), name='topup', iterfield=['in_file']) unwarp = pe.MapNode(fsl.ApplyTOPUP(in_index=[1], method='jac'), name='unwarp', iterfield=[ 'in_files', 'in_topup_fieldcoef', 'in_topup_movpar', 'encoding_file' ]) ########################################################################### # WORKFLOW ########################################################################### topup_workflow = pe.Workflow(name=name) # these are now mapnodes because they split up over files topup_workflow.connect(input_node, 'in_files', get_info, 'in_file') topup_workflow.connect(input_node, 'in_files', PE_ref, 'in_file') topup_workflow.connect(input_node, 'alt_files', PE_alt, 'in_file') # this is a simple node, connecting to the input node topup_workflow.connect(input_node, 'phase_encoding_direction', topup_scan_params_node, 'pe_direction') topup_workflow.connect(input_node, 'echo_time', topup_scan_params_node, 'te') topup_workflow.connect(input_node, 'epi_factor', topup_scan_params_node, 'epi_factor') # preparing a node here, which automatically iterates over dyns output of the get_info mapnode topup_workflow.connect(input_node, 'echo_time', apply_scan_params_node, 'te') topup_workflow.connect(input_node, 'phase_encoding_direction', apply_scan_params_node, 'pe_direction') topup_workflow.connect(input_node, 'epi_factor', apply_scan_params_node, 'epi_factor') topup_workflow.connect(get_info, 'dyns', apply_scan_params_node, 'nr_trs') # the nr_trs and in_files both propagate into the PR_ref node topup_workflow.connect(get_info, 'dyns', dyns_min_1_node, 'dyns') topup_workflow.connect(dyns_min_1_node, 'dyns_1', PE_ref, 't_min') topup_workflow.connect(PE_ref, 'roi_file', PE_comb, 'in1') topup_workflow.connect(PE_alt, 'roi_file', PE_comb, 'in2') topup_workflow.connect(PE_comb, 'out', PE_merge, 'in_files') topup_workflow.connect(topup_scan_params_node, 'fn', topup_node, 'encoding_file') topup_workflow.connect(PE_merge, 'merged_file', topup_node, 'in_file') topup_workflow.connect(input_node, 'conf_file', topup_node, 'config') topup_workflow.connect(input_node, 'in_files', unwarp, 'in_files') topup_workflow.connect(apply_scan_params_node, 'fn', unwarp, 'encoding_file') topup_workflow.connect(topup_node, 'out_fieldcoef', unwarp, 'in_topup_fieldcoef') topup_workflow.connect(topup_node, 'out_movpar', unwarp, 'in_topup_movpar') topup_workflow.connect(unwarp, 'out_corrected', output_node, 'out_files') topup_workflow.connect(topup_node, 'out_fieldcoef', output_node, 'field_coefs') # ToDo: automatic datasink? return topup_workflow
def sdc_peb_noddi(name='sdc_ped_noddi', epi_params=dict(echospacing=0.77e-3, acc_factor=3, enc_dir='y-', epi_factor=1), alt_epi_params=dict(echospacing=0.77e-3, acc_factor=3, enc_dir='y', epi_factor=1)): """ SDC stands for susceptibility distortion correction. PEB stands for phase-encoding-based. The phase-encoding-based (PEB) method implements SDC by acquiring diffusion images with two different enconding directions [Andersson2003]_. The most typical case is acquiring with opposed phase-gradient blips (e.g. *AP* and *PA*, or equivalently, *-y* and *y*) as in [Chiou2000]_, but it is also possible to use orthogonal configurations [Cordes2000]_ (e.g. *AP* and *LR*, or equivalently *-y* and *x*). This workflow uses the implementation of FSL (`TOPUP <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/TOPUP>`_). Example ------- from nipype.workflows.dmri.fsl.artifacts import sdc_peb .. admonition:: References .. [Andersson2003] Andersson JL et al., `How to correct susceptibility distortions in spin-echo echo-planar images: application to diffusion tensor imaging <http://dx.doi.org/10.1016/S1053-8119(03)00336-7>`_. Neuroimage. 2003 Oct;20(2):870-88. doi: 10.1016/S1053-8119(03)00336-7 .. [Cordes2000] Cordes D et al., Geometric distortion correction in EPI using two images with orthogonal phase-encoding directions, in Proc. ISMRM (8), p.1712, Denver, US, 2000. .. [Chiou2000] Chiou JY, and Nalcioglu O, A simple method to correct off-resonance related distortion in echo planar imaging, in Proc. ISMRM (8), p.1712, Denver, US, 2000. """ inputnode = pe.Node(niu.IdentityInterface( fields=['in_b0s', 'in_full_file', 'in_full_bvals']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'out_file', 'out_vsm', 'out_movpar', 'out_field_hz', 'out_enc_file', 'out_mask' ]), name='outputnode') avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'], output_names=['out_file'], function=b0_average), name='b0_avg') topup = pe.Node(fsl.TOPUP(), name='topup') # topup.inputs.encoding_direction = [epi_params['enc_dir'], # alt_epi_params['enc_dir']] readout = compute_readout(epi_params) readout_alt = compute_readout(alt_epi_params) # topup.inputs.readout_times = [readout, # readout_alt] topup_acq = pe.Node(niu.Function(input_names=[ 'in_file', 'epi_params', 'alt_epi_params', 'readout', 'readout_alt' ], output_names=['out_file'], function=gen_acq_noddi), name='generate_acq_txt_topup') topup_acq.inputs.epi_params = epi_params topup_acq.inputs.alt_epi_params = alt_epi_params topup_acq.inputs.readout = readout topup_acq.inputs.readout_alt = readout_alt undis_mask = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True), name='mask_from_topup') wf = pe.Workflow(name=name) wf.connect([(inputnode, topup, [('in_b0s', 'in_file')]), (inputnode, avg_b0, [('in_full_file', 'in_dwi'), ('in_full_bvals', 'in_bval')]), (avg_b0, undis_mask, [('out_file', 'in_file')]), (inputnode, topup_acq, [('in_b0s', 'in_file')]), (topup_acq, topup, [('out_file', 'encoding_file')]), (topup, outputnode, [('out_fieldcoef', 'out_vsm')]), (topup, outputnode, [('out_movpar', 'out_movpar')]), (topup, outputnode, [('out_corrected', 'out_file')]), (topup, outputnode, [('out_field', 'out_field_hz')]), (topup_acq, outputnode, [('out_file', 'out_enc_file')]), (undis_mask, outputnode, [('mask_file', 'out_mask')])]) return wf