def run_matlab(caps_dir, output_dir, subjects_visits_tsv, pipeline_parameters): """ Wrap the call of SurfStat using clinicasurfstat.m Matlab script. Args: caps_dir (str): CAPS directory containing surface-based features output_dir (str): Output directory that will contain outputs of clinicasurfstat.m subjects_visits_tsv (str): TSV file containing the GLM information pipeline_parameters (dict): parameters of StatisticsSurface pipeline """ import os from nipype.interfaces.matlab import MatlabCommand, get_matlab_command import clinica.pipelines as clinica_pipelines from clinica.utils.check_dependency import check_environment_variable from clinica.pipelines.statistics_surface.statistics_surface_utils import covariates_to_design_matrix, get_string_format_from_tsv path_to_matlab_script = os.path.join( os.path.dirname(clinica_pipelines.__path__[0]), 'lib', 'clinicasurfstat') freesurfer_home = check_environment_variable('FREESURFER_HOME', 'FreeSurfer') MatlabCommand.set_default_matlab_cmd(get_matlab_command()) matlab = MatlabCommand() matlab.inputs.paths = path_to_matlab_script matlab.inputs.script = """ clinicasurfstat('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', %.3f, '%s', %.3f, '%s', %.3f); """ % (os.path.join(caps_dir, 'subjects'), output_dir, subjects_visits_tsv, covariates_to_design_matrix(pipeline_parameters['contrast'], pipeline_parameters['covariates']), pipeline_parameters['contrast'], get_string_format_from_tsv(subjects_visits_tsv), pipeline_parameters['glm_type'], pipeline_parameters['group_label'], freesurfer_home, pipeline_parameters['custom_file'], pipeline_parameters['measure_label'], 'sizeoffwhm', pipeline_parameters['full_width_at_half_maximum'], 'thresholduncorrectedpvalue', 0.001, 'thresholdcorrectedpvalue', 0.05, 'clusterthreshold', pipeline_parameters['cluster_threshold']) # This will create a file: pyscript.m , the pyscript.m is the default name matlab.inputs.mfile = True # This will stop running with single thread matlab.inputs.single_comp_thread = False matlab.inputs.logfile = 'group-' + pipeline_parameters[ 'group_label'] + '_matlab.log' # cprint("Matlab logfile is located at the following path: %s" % matlab.inputs.logfile) # cprint("Matlab script command = %s" % matlab.inputs.script) # cprint("MatlabCommand inputs flag: single_comp_thread = %s" % matlab.inputs.single_comp_thread) # cprint("MatlabCommand choose which matlab to use(matlab_cmd): %s" % get_matlab_command()) matlab.run() return output_dir
def build_core_nodes(self): """Build and connect the core nodes of the pipeline.""" import os import nipype.interfaces.fsl as fsl import nipype.interfaces.mrtrix as mrtrix import nipype.interfaces.utility as nutil import nipype.pipeline.engine as npe from nipype.interfaces.ants import ApplyTransforms, RegistrationSynQuick from nipype.interfaces.mrtrix.preprocess import DWI2Tensor from clinica.lib.nipype.interfaces.mrtrix3.utils import TensorMetrics from clinica.utils.check_dependency import check_environment_variable from .dwi_dti_utils import ( extract_bids_identifier_from_caps_filename, get_ants_transforms, get_caps_filenames, print_begin_pipeline, print_end_pipeline, statistics_on_atlases, ) # Nodes creation # ============== get_bids_identifier = npe.Node( interface=nutil.Function( input_names=["caps_dwi_filename"], output_names=["bids_identifier"], function=extract_bids_identifier_from_caps_filename, ), name="0-Get_BIDS_Identifier", ) get_caps_filenames = npe.Node( interface=nutil.Function( input_names=["caps_dwi_filename"], output_names=[ "bids_source", "out_dti", "out_fa", "out_md", "out_ad", "out_rd", "out_evec", ], function=get_caps_filenames, ), name="0-CAPS_Filenames", ) convert_gradients = npe.Node(interface=mrtrix.FSL2MRTrix(), name="0-Convert_FSL_Gradient") dwi_to_dti = npe.Node(interface=DWI2Tensor(), name="1-Compute_DTI") dti_to_metrics = npe.Node(interface=TensorMetrics(), name="2-DTI-based_Metrics") register_fa = npe.Node(interface=RegistrationSynQuick(), name="3a-Register_FA") fsl_dir = check_environment_variable("FSLDIR", "FSL") fa_map = os.path.join(fsl_dir, "data", "atlases", "JHU", "JHU-ICBM-FA-1mm.nii.gz") register_fa.inputs.fixed_image = fa_map ants_transforms = npe.Node( interface=nutil.Function( input_names=[ "in_affine_transformation", "in_bspline_transformation" ], output_names=["transforms"], function=get_ants_transforms, ), name="combine_ants_transforms", ) apply_ants_registration = npe.Node(interface=ApplyTransforms(), name="apply_ants_registration") apply_ants_registration.inputs.dimension = 3 apply_ants_registration.inputs.input_image_type = 0 apply_ants_registration.inputs.interpolation = "Linear" apply_ants_registration.inputs.reference_image = fa_map apply_ants_registration_for_md = apply_ants_registration.clone( "3b-Apply_ANTs_Registration_MD") apply_ants_registration_for_ad = apply_ants_registration.clone( "3b-Apply_ANTs_Registration_AD") apply_ants_registration_for_rd = apply_ants_registration.clone( "3b-Apply_ANTs_Registration_RD") thres_map = npe.Node(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="RemoveNegative") thres_norm_fa = thres_map.clone("3c-RemoveNegative_FA") thres_norm_md = thres_map.clone("3c-RemoveNegative_MD") thres_norm_ad = thres_map.clone("3c-RemoveNegative_AD") thres_norm_rd = thres_map.clone("3c-RemoveNegative_RD") scalar_analysis = npe.Node( interface=nutil.Function( input_names=["in_registered_map", "name_map", "prefix_file"], output_names=["atlas_statistics_list"], function=statistics_on_atlases, ), name="4-Scalar_Analysis", ) scalar_analysis_fa = scalar_analysis.clone("4-Scalar_Analysis_FA") scalar_analysis_fa.inputs.name_map = "FA" scalar_analysis_md = scalar_analysis.clone("4-Scalar_Analysis_MD") scalar_analysis_md.inputs.name_map = "MD" scalar_analysis_ad = scalar_analysis.clone("4-Scalar_Analysis_AD") scalar_analysis_ad.inputs.name_map = "AD" scalar_analysis_rd = scalar_analysis.clone("4-Scalar_Analysis_RD") scalar_analysis_rd.inputs.name_map = "RD" thres_map = npe.Node(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="5-Remove_Negative") thres_fa = thres_map.clone("5-Remove_Negative_FA") thres_md = thres_map.clone("5-Remove_Negative_MD") thres_ad = thres_map.clone("5-Remove_Negative_AD") thres_rd = thres_map.clone("5-Remove_Negative_RD") thres_decfa = thres_map.clone("5-Remove_Negative_DECFA") print_begin_message = npe.Node( interface=nutil.Function(input_names=["in_bids_or_caps_file"], function=print_begin_pipeline), name="Write-Begin_Message", ) print_end_message = npe.Node( interface=nutil.Function( input_names=[ "in_bids_or_caps_file", "final_file_1", "final_file_2" ], function=print_end_pipeline, ), name="Write-End_Message", ) # Connection # ========== # fmt: off self.connect([ (self.input_node, get_caps_filenames, [("preproc_dwi", "caps_dwi_filename")]), # Print begin message (self.input_node, print_begin_message, [("preproc_dwi", "in_bids_or_caps_file")]), # Get BIDS/CAPS identifier from filename (self.input_node, get_bids_identifier, [("preproc_dwi", "caps_dwi_filename")]), # Convert FSL gradient files (bval/bvec) to MRtrix format (self.input_node, convert_gradients, [("preproc_bval", "bval_file"), ("preproc_bvec", "bvec_file")]), # Computation of the DTI model (self.input_node, dwi_to_dti, [("b0_mask", "mask"), ("preproc_dwi", "in_file")]), (convert_gradients, dwi_to_dti, [("encoding_file", "encoding_file") ]), (get_caps_filenames, dwi_to_dti, [("out_dti", "out_filename")]), # Computation of the different metrics from the DTI (get_caps_filenames, dti_to_metrics, [("out_fa", "out_fa")]), (get_caps_filenames, dti_to_metrics, [("out_md", "out_adc")]), (get_caps_filenames, dti_to_metrics, [("out_ad", "out_ad")]), (get_caps_filenames, dti_to_metrics, [("out_rd", "out_rd")]), (get_caps_filenames, dti_to_metrics, [("out_evec", "out_evec")]), (self.input_node, dti_to_metrics, [("b0_mask", "in_mask")]), (dwi_to_dti, dti_to_metrics, [("tensor", "in_file")]), # Registration of FA-map onto the atlas: (dti_to_metrics, register_fa, [("out_fa", "moving_image")]), # Apply deformation field on MD, AD & RD: (register_fa, ants_transforms, [("out_matrix", "in_affine_transformation")]), (register_fa, ants_transforms, [("forward_warp_field", "in_bspline_transformation")]), (dti_to_metrics, apply_ants_registration_for_md, [("out_adc", "input_image")]), (ants_transforms, apply_ants_registration_for_md, [("transforms", "transforms")]), (dti_to_metrics, apply_ants_registration_for_ad, [("out_ad", "input_image")]), (ants_transforms, apply_ants_registration_for_ad, [("transforms", "transforms")]), (dti_to_metrics, apply_ants_registration_for_rd, [("out_rd", "input_image")]), (ants_transforms, apply_ants_registration_for_rd, [("transforms", "transforms")]), # Remove negative values from the DTI maps: (register_fa, thres_norm_fa, [("warped_image", "in_file")]), (apply_ants_registration_for_md, thres_norm_md, [("output_image", "in_file")]), (apply_ants_registration_for_rd, thres_norm_rd, [("output_image", "in_file")]), (apply_ants_registration_for_ad, thres_norm_ad, [("output_image", "in_file")]), # Generate regional TSV files (get_bids_identifier, scalar_analysis_fa, [("bids_identifier", "prefix_file")]), (thres_norm_fa, scalar_analysis_fa, [("out_file", "in_registered_map")]), (get_bids_identifier, scalar_analysis_md, [("bids_identifier", "prefix_file")]), (thres_norm_md, scalar_analysis_md, [("out_file", "in_registered_map")]), (get_bids_identifier, scalar_analysis_ad, [("bids_identifier", "prefix_file")]), (thres_norm_ad, scalar_analysis_ad, [("out_file", "in_registered_map")]), (get_bids_identifier, scalar_analysis_rd, [("bids_identifier", "prefix_file")]), (thres_norm_rd, scalar_analysis_rd, [("out_file", "in_registered_map")]), # Remove negative values from the DTI maps: (get_caps_filenames, thres_fa, [("out_fa", "out_file")]), (dti_to_metrics, thres_fa, [("out_fa", "in_file")]), (get_caps_filenames, thres_md, [("out_md", "out_file")]), (dti_to_metrics, thres_md, [("out_adc", "in_file")]), (get_caps_filenames, thres_ad, [("out_ad", "out_file")]), (dti_to_metrics, thres_ad, [("out_ad", "in_file")]), (get_caps_filenames, thres_rd, [("out_rd", "out_file")]), (dti_to_metrics, thres_rd, [("out_rd", "in_file")]), (get_caps_filenames, thres_decfa, [("out_evec", "out_file")]), (dti_to_metrics, thres_decfa, [("out_evec", "in_file")]), # Outputnode (dwi_to_dti, self.output_node, [("tensor", "dti")]), (thres_fa, self.output_node, [("out_file", "fa")]), (thres_md, self.output_node, [("out_file", "md")]), (thres_ad, self.output_node, [("out_file", "ad")]), (thres_rd, self.output_node, [("out_file", "rd")]), (thres_decfa, self.output_node, [("out_file", "decfa")]), (register_fa, self.output_node, [("out_matrix", "affine_matrix")]), (register_fa, self.output_node, [("forward_warp_field", "b_spline_transform")]), (thres_norm_fa, self.output_node, [("out_file", "registered_fa")]), (thres_norm_md, self.output_node, [("out_file", "registered_md")]), (thres_norm_ad, self.output_node, [("out_file", "registered_ad")]), (thres_norm_rd, self.output_node, [("out_file", "registered_rd")]), (scalar_analysis_fa, self.output_node, [("atlas_statistics_list", "statistics_fa")]), (scalar_analysis_md, self.output_node, [("atlas_statistics_list", "statistics_md")]), (scalar_analysis_ad, self.output_node, [("atlas_statistics_list", "statistics_ad")]), (scalar_analysis_rd, self.output_node, [("atlas_statistics_list", "statistics_rd")]), # Print end message (self.input_node, print_end_message, [("preproc_dwi", "in_bids_or_caps_file")]), (thres_rd, print_end_message, [("out_file", "final_file_1")]), (scalar_analysis_rd, print_end_message, [("atlas_statistics_list", "final_file_2")]), ])
def register_dti_maps_on_atlas( working_directory=None, name="register_dti_maps_on_atlas"): """ Register FA-map on a subject towards a FA atlas and apply the estimated deformation to MD, AD & RD. This pipelines performs the analysis of tracts using a white matter atlas and computes mean value of the scalar on each tracts of this atlas. The pipelines registers the FA-map of a subject onto the FA-map of the atlas thanks to antsRegistrationSyNQuick. Then, the estimated deformation is applied to the MD-map, AD-map and RD-map. Finally, the labelled atlas is used to compute the statistics of each scalar on each tract of the white matter atlas. Args: working_directory (Optional[str]): Directory where the temporary results are stored. If not specified, it is automatically generated (generally in /tmp/). name (Optional[str]): Name of the pipelines. Inputnode: in_fa (str): FA-map of the subject in native space. in_md (str): MD-map of the subject in native space. in_ad (str): AD-map of the subject in native space. in_rd (str): RD-map of the subject in native space. Outputnode: out_affine_transform (str): Affine transformation matrix obtained by antsRegistrationSyNQuick after registration towards <atlas_name>. out_b_spline_transform (str): BSpline transformation obtained by antsRegistrationSyNQuick after registration towards <atlas_name>. out_norm_fa (str): FA-map registered on <atlas_name>. out_norm_md (str): MD-map registered on <atlas_name>. out_norm_ad (str): AD-map registered on <atlas_name>. out_norm_rd (str): RD-map registered on <atlas_name>. """ import os import tempfile import nipype.interfaces.fsl as fsl import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from nipype.interfaces.ants import RegistrationSynQuick from clinica.utils.atlas import AtlasAbstract, JHUDTI811mm from clinica.utils.mri_registration import apply_ants_registration_syn_quick_transformation from clinica.utils.check_dependency import check_environment_variable atlas = JHUDTI811mm() if not isinstance(atlas, AtlasAbstract): raise Exception("Atlas element must be an AtlasAbstract type") if working_directory is None: working_directory = tempfile.mkdtemp() inputnode = pe.Node(niu.IdentityInterface( fields=['in_fa', 'in_md', 'in_ad', 'in_rd', 'in_atlas_scalar_image']), name='inputnode') fsl_dir = check_environment_variable('FSLDIR', 'FSL') fa_map = os.path.join(fsl_dir, 'data', 'atlases', 'JHU', 'JHU-ICBM-FA-1mm.nii.gz') inputnode.inputs.in_atlas_scalar_image = fa_map register_fa = pe.Node( interface=RegistrationSynQuick(), name='register_fa') apply_ants_registration_for_md = pe.Node(interface=niu.Function( input_names=['in_image', 'in_reference_image', 'in_affine_transformation', 'in_bspline_transformation', 'name_output_image'], output_names=['out_deformed_image'], function=apply_ants_registration_syn_quick_transformation), name='apply_ants_registration_for_md') apply_ants_registration_for_md.inputs.name_output_image = \ 'space-' + atlas.get_name_atlas() + '_res-' + atlas.get_spatial_resolution() + '_MD.nii.gz' apply_ants_registration_for_ad = pe.Node(interface=niu.Function( input_names=['in_image', 'in_reference_image', 'in_affine_transformation', 'in_bspline_transformation', 'name_output_image'], output_names=['out_deformed_image'], function=apply_ants_registration_syn_quick_transformation), name='apply_ants_registration_for_ad') apply_ants_registration_for_ad.inputs.name_output_image = \ 'space-' + atlas.get_name_atlas() + '_res-' + atlas.get_spatial_resolution() + '_AD.nii.gz' apply_ants_registration_for_rd = pe.Node(interface=niu.Function( input_names=['in_image', 'in_reference_image', 'in_affine_transformation', 'in_bspline_transformation', 'name_output_image'], output_names=['out_deformed_image'], function=apply_ants_registration_syn_quick_transformation), name='apply_ants_registration_for_rd') apply_ants_registration_for_rd.inputs.name_output_image = \ 'space-' + atlas.get_name_atlas() + '_res-' + atlas.get_spatial_resolution() + '_RD.nii.gz' thres_map = pe.Node(fsl.Threshold(thresh=0.0), iterfield=['in_file'], name='RemoveNegative') thres_fa = thres_map.clone('RemoveNegative_FA') thres_md = thres_map.clone('RemoveNegative_MD') thres_ad = thres_map.clone('RemoveNegative_AD') thres_rd = thres_map.clone('RemoveNegative_RD') outputnode = pe.Node(niu.IdentityInterface( fields=['out_norm_fa', 'out_norm_md', 'out_norm_ad', 'out_norm_rd', 'out_affine_matrix', 'out_b_spline_transform']), name='outputnode') wf = pe.Workflow(name=name, base_dir=working_directory) wf.connect([ # Registration of FA-map onto the atlas: (inputnode, register_fa, [('in_fa', 'moving_image'), # noqa ('in_atlas_scalar_image', 'fixed_image')]), # noqa # Apply deformation field on MD, AD & RD: (inputnode, apply_ants_registration_for_md, [('in_md', 'in_image')]), # noqa (inputnode, apply_ants_registration_for_md, [('in_atlas_scalar_image', 'in_reference_image')]), # noqa (register_fa, apply_ants_registration_for_md, [('out_matrix', 'in_affine_transformation')]), # noqa (register_fa, apply_ants_registration_for_md, [('forward_warp_field', 'in_bspline_transformation')]), # noqa (inputnode, apply_ants_registration_for_ad, [('in_ad', 'in_image')]), # noqa (inputnode, apply_ants_registration_for_ad, [('in_atlas_scalar_image', 'in_reference_image')]), # noqa (register_fa, apply_ants_registration_for_ad, [('out_matrix', 'in_affine_transformation')]), # noqa (register_fa, apply_ants_registration_for_ad, [('forward_warp_field', 'in_bspline_transformation')]), # noqa (inputnode, apply_ants_registration_for_rd, [('in_rd', 'in_image')]), # noqa (inputnode, apply_ants_registration_for_rd, [('in_atlas_scalar_image', 'in_reference_image')]), # noqa (register_fa, apply_ants_registration_for_rd, [('out_matrix', 'in_affine_transformation')]), # noqa (register_fa, apply_ants_registration_for_rd, [('forward_warp_field', 'in_bspline_transformation')]), # noqa # Remove negative values from the DTI maps: (register_fa, thres_fa, [('warped_image', 'in_file')]), # noqa (apply_ants_registration_for_md, thres_md, [('out_deformed_image', 'in_file')]), # noqa (apply_ants_registration_for_rd, thres_rd, [('out_deformed_image', 'in_file')]), # noqa (apply_ants_registration_for_ad, thres_ad, [('out_deformed_image', 'in_file')]), # noqa # Outputnode: (thres_fa, outputnode, [('out_file', 'out_norm_fa')]), # noqa (register_fa, outputnode, [('out_matrix', 'out_affine_matrix'), # noqa ('forward_warp_field', 'out_b_spline_transform'), # noqa ('inverse_warp_field', 'out_inverse_warp')]), # noqa (thres_md, outputnode, [('out_file', 'out_norm_md')]), # noqa (thres_ad, outputnode, [('out_file', 'out_norm_ad')]), # noqa (thres_rd, outputnode, [('out_file', 'out_norm_rd')]) # noqa ]) return wf