Пример #1
0
def bids_autofind(
    bids_dir,
    modality='',
    path_template="{bids_dir}/sub-{{subject}}/ses-{{session}}/{modality}/sub-{{subject}}_ses-{{session}}_task-{{task}}_acq-{{acquisition}}.nii.gz",
    match_regex='',
):
    """Automatically generate a BIDS path template and a substitution iterator (list of dicts, as produced by `samri.utilities.bids_substitution_iterator`, and used as a standard input SAMRI function input) from a BIDS-respecting directory.

	Parameters
	----------
	bids_dir : str
		Path to BIDS-formatted directory
	modality : {"func", "anat"}
		Which modality to source data for (currently only supports "func", and "anat" - ideally we could extend this to include "dwi").

	Returns
	-------
	path_template : str
		String which can be formatted with any of the dictionaries in `substitutions`
	substitutions : list of dicti
		A substitution iterator usable as a standard SAMRI function input, which (together with `path_template`) unambiguoulsy identifies input files for analysis.
	"""

    bids_dir = path.abspath(path.expanduser(bids_dir))

    if match_regex:
        pass
    elif modality in ("func", "dwi"):
        match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/' + modality + '/.*?_task-(?P<task>.+).*?_acq-(?P<acquisition>.+)\.nii.gz'
    elif modality == "":
        match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/.*?_task-(?P<task>.+).*?_acq-(?P<acquisition>.+).*?\.nii.gz'
    elif modality == "anat":
        match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/anat/.*?_(?P<task>.+).*?_acq-(?P<acquisition>.+)\.nii.gz'

    path_template = path_template.format(bids_dir=bids_dir, modality=modality)

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = bids_dir
    datafind.inputs.match_regex = match_regex
    datafind_res = datafind.run()

    substitutions = []
    for ix, i in enumerate(datafind_res.outputs.out_paths):
        substitution = {}
        substitution["acquisition"] = datafind_res.outputs.acquisition[ix]
        substitution["subject"] = datafind_res.outputs.sub[ix]
        substitution["session"] = datafind_res.outputs.ses[ix]
        substitution["task"] = datafind_res.outputs.task[ix]
        if path_template.format(**substitution) != i:
            print("Original DataFinder path: " + i)
            print("Reconstructed path:       " +
                  path_template.format(**substitution))
            raise ValueError(
                "The reconstructed file path based on the substitution dictionary and the path template, is not identical to the corresponding path, found by `nipype.interfaces.io.DataFinder`. See string values above."
            )
        substitutions.append(substitution)

    return path_template, substitutions
Пример #2
0
def test_datafinder_unpack(tmpdir):
    outdir = tmpdir.strpath
    single_res = os.path.join(outdir, "findme.txt")
    open(single_res, 'a').close()
    open(os.path.join(outdir, "dontfindme"), 'a').close()

    df = nio.DataFinder()
    df.inputs.root_paths = outdir
    df.inputs.match_regex = '.+/(?P<basename>.+)\.txt'
    df.inputs.unpack_single = True
    result = df.run()
    print(result.outputs.out_paths)
    assert result.outputs.out_paths == single_res
Пример #3
0
def get_scores(
    bids_dir,
    reference,
    modality="func",
    save_as=False,
):

    #ideally at some point, we would also support dwi
    allowed_modalities = ("func", "anat")
    if modality not in allowed_modalities:
        raise ValueError("modality parameter needs to be one of " +
                         ", ".join(allowed_modalities) + ".")

    bids_dir = path.abspath(path.expanduser(bids_dir))
    reference = path.abspath(path.expanduser(reference))

    if modality in ("func", "dwi"):
        match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/' + modality + '/.*?_trial-(?P<trial>.+)\.nii.gz'
    elif modality == "anat":
        match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/anat/.*?_(?P<trial>.+)\.nii.gz'

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = bids_dir
    datafind.inputs.match_regex = match_regex
    datafind_res = datafind.run()
    files_data = []

    n_jobs = mp.cpu_count() - 2
    similarity_data = Parallel(n_jobs=n_jobs, verbose=0, backend="threading")(
        map(
            delayed(measure_sim),
            datafind_res.outputs.out_paths,
            datafind_res.outputs.ses,
            datafind_res.outputs.sub,
            datafind_res.outputs.trial,
            [modality] * len(datafind_res.outputs.out_paths),
            [reference] * len(datafind_res.outputs.out_paths),
        ))

    df = pd.DataFrame.from_dict(similarity_data)

    if save_as:
        save_as = path.abspath(path.expanduser(save_as))
        if save_as.lower().endswith('.csv'):
            df.to_csv(save_as)
        else:
            raise ValueError(
                "Please specify an output path ending in any one of " +
                ",".join((".csv", )) + ".")
Пример #4
0
def test_datafinder_depth(tmpdir):
    outdir = str(tmpdir)
    os.makedirs(os.path.join(outdir, '0', '1', '2', '3'))

    df = nio.DataFinder()
    df.inputs.root_paths = os.path.join(outdir, '0')
    for min_depth in range(4):
        for max_depth in range(min_depth, 4):
            df.inputs.min_depth = min_depth
            df.inputs.max_depth = max_depth
            result = df.run()
            expected = ['{}'.format(x) for x in range(min_depth, max_depth + 1)]
            for path, exp_fname in zip(result.outputs.out_paths, expected):
                _, fname = os.path.split(path)
                assert fname == exp_fname
Пример #5
0
def test_datafinder_depth(tmpdir):
    outdir = tmpdir.strpath
    os.makedirs(os.path.join(outdir, "0", "1", "2", "3"))

    df = nio.DataFinder()
    df.inputs.root_paths = os.path.join(outdir, "0")
    for min_depth in range(4):
        for max_depth in range(min_depth, 4):
            df.inputs.min_depth = min_depth
            df.inputs.max_depth = max_depth
            result = df.run()
            expected = [
                "{}".format(x) for x in range(min_depth, max_depth + 1)
            ]
            for path, exp_fname in zip(result.outputs.out_paths, expected):
                _, fname = os.path.split(path)
                assert fname == exp_fname
Пример #6
0
def seed_based(
    bids_base,
    seed_mask=None,
    debug=False,
    exclude={},
    include={},
    keep_crashdump=False,
    keep_work=False,
    match_regex='.+/sub-(?P<sub>[a-zA-Z0-9]+)/ses-(?P<ses>[a-zA-Z0-9]+)/.*?_acq-(?P<acq>[a-zA-Z0-9]+)_task-(?P<task>[a-zA-Z0-9]+)_(?P<mod>[a-zA-Z0-9]+).(?:nii|nii\.gz)',
    n_procs=N_PROCS,
    workflow_name="diagnostic",
):
    '''Create seed-based functional connectivity maps based on a GLM timecourse analysis (with FSL's FLAMEO) for a given seed mask and a given BIDS-formatted directory tree.

	Parameters
	----------

	bids_base : string, optional
		Path to the top level of a BIDS directory tree for which to perform the diagnostic.
	debug : bool, optional
		Enable full nipype debugging support for the workflow construction and execution.
	exclude : dict, optional
		A dictionary with any subset of 'subject', 'session', 'acquisition', 'task', 'modality', and 'path' as keys and corresponding identifiers as values.
		This is a blacklist: if this is specified only non-matching entries will be included in the analysis.
	include : dict, optional
		A dictionary with any subset of 'subject', 'session', 'acquisition', 'task', 'modality', and 'path' as keys and corresponding identifiers as values.
		This is a whitelist: if this is specified only matching entries will be included in the analysis.
	keep_crashdump : bool, optional
		Whether to keep the crashdump directory (containing all the crash reports for intermediary workflow steps, as managed by nipypye).
		This is useful for debugging and quality control.
	keep_work : bool, optional
		Whether to keep the work directory (containing all the intermediary workflow steps, as managed by nipypye).
		This is useful for debugging and quality control.
	match_regex : str, optional
		Regex matching pattern by which to select input files. Has to contain groups named "sub", "ses", "acq", "task", and "mod".
	n_procs : int, optional
		Maximum number of processes which to simultaneously spawn for the workflow.
		If not explicitly defined, this is automatically calculated from the number of available cores and under the assumption that the workflow will be the main process running for the duration that it is running.
	workflow_name : string, optional
		Name of the workflow execution. The output will be saved one level above the bids_base, under a directory bearing the name given here.
	'''

    bids_base = path.abspath(path.expanduser(bids_base))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = bids_base
    datafind.inputs.match_regex = match_regex
    datafind_res = datafind.run()

    data_selection = zip(*[
        datafind_res.outputs.sub, datafind_res.outputs.ses,
        datafind_res.outputs.acq, datafind_res.outputs.task,
        datafind_res.outputs.mod, datafind_res.outputs.out_paths
    ])
    data_selection = [list(i) for i in data_selection]
    data_selection = pd.DataFrame(data_selection,
                                  columns=('subject', 'session', 'acquisition',
                                           'task', 'modality', 'path'))

    data_selection = data_selection.sort_values(['session', 'subject'],
                                                ascending=[1, 1])
    if exclude:
        for key in exclude:
            data_selection = data_selection[~data_selection[key].
                                            isin(exclude[key])]
    if include:
        for key in include:
            data_selection = data_selection[data_selection[key].isin(
                include[key])]

    data_selection['out_path'] = ''
    if data_selection['path'].str.contains('.nii.gz').any():
        data_selection['out_path'] = data_selection['path'].apply(
            lambda x: path.basename(
                path.splitext(path.splitext(x)[0])[0] + '_MELODIC'))
    else:
        data_selection['out_path'] = data_selection['path'].apply(
            lambda x: path.basename(path.splitext(x)[0] + '_MELODIC'))

    paths = data_selection['path']

    infosource = pe.Node(interface=util.IdentityInterface(
        fields=['path'], mandatory_inputs=False),
                         name="infosource")
    infosource.iterables = [('path', paths)]

    dummy_scans = pe.Node(
        name='dummy_scans',
        interface=util.Function(
            function=force_dummy_scans,
            input_names=inspect.getargspec(force_dummy_scans)[0],
            output_names=['out_file']))
    dummy_scans.inputs.desired_dummy_scans = 10

    bids_filename = pe.Node(name='bids_filename',
                            interface=util.Function(
                                function=out_path,
                                input_names=inspect.getargspec(out_path)[0],
                                output_names=['filename']))
    bids_filename.inputs.selection_df = data_selection

    bids_container = pe.Node(name='path_container',
                             interface=util.Function(
                                 function=container,
                                 input_names=inspect.getargspec(container)[0],
                                 output_names=['container']))
    bids_container.inputs.selection_df = data_selection

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.abspath(
        path.join(bids_base, '..', 'diagnostic'))
    datasink.inputs.parameterization = False

    report_tr = pe.Node(name='report_tr',
                        interface=util.Function(
                            function=get_tr,
                            input_names=inspect.getargspec(get_tr)[0],
                            output_names=['tr']))
    report_tr.inputs.ndim = 4

    workflow_connections = [
        (infosource, dummy_scans, [('path', 'in_file')]),
        (infosource, bids_filename, [('path', 'in_path')]),
        (bids_filename, bids_container, [('filename', 'out_path')]),
        (bids_container, datasink, [('container', 'container')]),
        (infosource, report_tr, [('path', 'in_file')]),
        (report_tr, melodic, [('tr', 'tr_sec')]),
    ]

    crashdump_dir = path.abspath(
        path.join(bids_base, '..', 'diagnostic_crashdump'))
    workflow_config = {'execution': {'crashdump_dir': crashdump_dir}}
    if debug:
        workflow_config['logging'] = {
            'workflow_level': 'DEBUG',
            'utils_level': 'DEBUG',
            'interface_level': 'DEBUG',
            'filemanip_level': 'DEBUG',
            'log_to_file': 'true',
        }

    workdir_name = 'diagnostic_work'
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.base_dir = path.abspath(path.join(bids_base, '..'))
    workflow.config = workflow_config
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    if not keep_work or not keep_crashdump:
        try:
            workflow.run(plugin="MultiProc", plugin_args={'n_procs': n_procs})
        except RuntimeError:
            pass
    else:
        workflow.run(plugin="MultiProc", plugin_args={'n_procs': n_procs})
    if not keep_work:
        shutil.rmtree(path.join(workflow.base_dir, workdir_name))
    if not keep_crashdump:
        try:
            shutil.rmtree(crashdump_dir)
        except FileNotFoundError:
            pass

    return
Пример #7
0
Файл: glm.py Проект: Doeme/SAMRI
def l2_common_effect(
    l1_dir,
    exclude={},
    groupby="session",
    keep_work=False,
    l2_dir="",
    loud=False,
    tr=1,
    nprocs=6,
    workflow_name="generic",
    mask="/home/chymera/ni_data/templates/ds_QBI_chr_bin.nii.gz",
):

    l1_dir = path.expanduser(l1_dir)
    if not l2_dir:
        l2_dir = path.abspath(path.join(l1_dir, "..", "..", "l2"))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = l1_dir
    datafind.inputs.match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/.*?_trial-(?P<scan>.+)_cope\.nii.gz'
    datafind_res = datafind.run()
    subjects = set(datafind_res.outputs.sub)
    sessions = set(datafind_res.outputs.ses)
    scans = set(datafind_res.outputs.scan)

    copemerge = pe.Node(interface=fsl.Merge(dimension='t'), name="copemerge")
    varcopemerge = pe.Node(interface=fsl.Merge(dimension='t'),
                           name="varcopemerge")

    level2model = pe.Node(interface=fsl.L2Model(), name='level2model')

    flameo = pe.Node(interface=fsl.FLAMEO(), name="flameo")
    flameo.inputs.mask_file = mask
    flameo.inputs.run_mode = "ols"

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.join(l2_dir, workflow_name)
    datasink.inputs.substitutions = [
        ('_iterable_', ''),
    ]

    if groupby == "subject":
        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['iterable']),
            name="infosource")
        infosource.iterables = [('iterable', subjects)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "group",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[['group', 'group']],
                                               varcbs=[['group', 'group']])
        datasource.inputs.field_template = dict(
            copes="sub-%s/ses-*/sub-%s_ses-*_trial-*_cope.nii.gz",
            varcbs="sub-%s/ses-*/sub-%s_ses-*_trial-*_varcb.nii.gz",
        )
        workflow_connections = [
            (infosource, datasource, [('iterable', 'group')]),
            (infosource, copemerge, [(('iterable', add_suffix, "_cope.nii.gz"),
                                      'merged_file')]),
            (infosource, varcopemerge, [(('iterable', add_suffix,
                                          "_varcb.nii.gz"), 'merged_file')]),
        ]
    elif groupby == "subject_scan":
        #does not currently work, due to missing iterator combinations (same issue as preprocessing)
        merge = pe.Node(interface=util.Merge(2), name="merge")
        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['subject', 'scan']),
            name="infosource")
        infosource.iterables = [('subject', subjects), ('scan', scans)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "subject",
                "scan",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[[
            "subject",
            "subject",
            "scan",
        ]],
                                               varcbs=[[
                                                   "subject",
                                                   "subject",
                                                   "scan",
                                               ]])
        datasource.inputs.field_template = dict(
            copes="sub-%s/ses-*/sub-%s_ses-*_trial-%s_cope.nii.gz",
            varcbs="sub-%s/ses-*/sub-%s_ses-*_trial-%s_varcb.nii.gz",
        )
        workflow_connections = [
            (infosource, datasource, [('subject', 'subject'),
                                      ('scan', 'scan')]),
            (infosource, merge, [('subject', 'in1'), ('scan', 'in2')]),
            (merge, copemerge, [(('out', add_suffix, "_cope.nii.gz"),
                                 'merged_file')]),
            (merge, varcopemerge, [(('out', add_suffix, "_varcb.nii.gz"),
                                    'merged_file')]),
        ]
    elif groupby == "session":
        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['iterable']),
            name="infosource")
        infosource.iterables = [('iterable', sessions)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "group",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[['group', 'group']],
                                               varcbs=[['group', 'group']])
        datasource.inputs.field_template = dict(
            copes="sub-*/ses-%s/sub-*_ses-%s_trial-*_cope.nii.gz",
            varcbs="sub-*/ses-%s/sub-*_ses-%s_trial-*_varcb.nii.gz",
        )
        workflow_connections = [
            (infosource, datasource, [('iterable', 'group')]),
            (infosource, copemerge, [(('iterable', add_suffix, "_cope.nii.gz"),
                                      'merged_file')]),
            (infosource, varcopemerge, [(('iterable', add_suffix,
                                          "_varcb.nii.gz"), 'merged_file')]),
        ]
    elif groupby == "scan":
        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['iterable']),
            name="infosource")
        infosource.iterables = [('iterable', scans)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "group",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[['group']],
                                               varcbs=[['group']])
        datasource.inputs.field_template = dict(
            copes="sub-*/ses-*/sub-*_ses-*_trial-%s_cope.nii.gz ",
            varcbs="sub-*/ses-*/sub-*_ses-*_trial-%s_varcb.nii.gz ",
        )
        workflow_connections = [
            (infosource, datasource, [('iterable', 'group')]),
            (infosource, copemerge, [(('iterable', add_suffix, "_cope.nii.gz"),
                                      'merged_file')]),
            (infosource, varcopemerge, [(('iterable', add_suffix,
                                          "_varcb.nii.gz"), 'merged_file')]),
        ]
    datasource.inputs.base_directory = l1_dir
    datasource.inputs.sort_filelist = True
    datasource.inputs.template = "*"

    workflow_connections.extend([
        (datasource, copemerge, [(('copes', datasource_exclude, exclude),
                                  'in_files')]),
        (datasource, varcopemerge, [(('varcbs', datasource_exclude, exclude),
                                     'in_files')]),
        (datasource, level2model, [(('copes', datasource_exclude, exclude,
                                     "len"), 'num_copes')]),
        (copemerge, flameo, [('merged_file', 'cope_file')]),
        (varcopemerge, flameo, [('merged_file', 'var_cope_file')]),
        (level2model, flameo, [('design_mat', 'design_file')]),
        (level2model, flameo, [('design_grp', 'cov_split_file')]),
        (level2model, flameo, [('design_con', 't_con_file')]),
        (flameo, datasink, [('copes', '@copes')]),
        (flameo, datasink, [('fstats', '@fstats')]),
        (flameo, datasink, [('tstats', '@tstats')]),
        (flameo, datasink, [('zstats', '@zstats')]),
    ])

    workdir_name = workflow_name + "_work"
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.config = {
        "execution": {
            "crashdump_dir": path.join(l2_dir, "crashdump")
        }
    }
    workflow.base_dir = l2_dir
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    if not loud:
        try:
            workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})
        except RuntimeError:
            print(
                "WARNING: Some expected scans have not been found (or another RuntimeError has occured)."
            )
        for f in listdir(getcwd()):
            if re.search("crash.*?-varcopemerge|-copemerge.*", f):
                remove(path.join(getcwd(), f))
    else:
        workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})

    if not keep_work:
        shutil.rmtree(path.join(l2_dir, workdir_name))
Пример #8
0
Файл: glm.py Проект: Doeme/SAMRI
def l1(
    preprocessing_dir,
    highpass_sigma=225,
    include={},
    exclude={},
    keep_work=False,
    l1_dir="",
    nprocs=10,
    mask="/home/chymera/ni_data/templates/ds_QBI_chr_bin.nii.gz",
    per_stimulus_contrast=False,
    habituation="",
    tr=1,
    workflow_name="generic",
):
    """Calculate subject level GLM statistics.

	Parameters
	----------

	include : dict
	A dictionary with any combination of "sessions", "subjects", "trials" as keys and corresponding identifiers as values.
	If this is specified ony matching entries will be included in the analysis.

	exclude : dict
	A dictionary with any combination of "sessions", "subjects", "trials" as keys and corresponding identifiers as values.
	If this is specified ony non-matching entries will be included in the analysis.

	habituation : string
	One value of "confound", "in_main_contrast", "separate_contrast", "" indicating how the habituation regressor should be handled.
	"" or any other value which evaluates to False will mean no habituation regressor is used int he model
	"""

    preprocessing_dir = path.expanduser(preprocessing_dir)
    if not l1_dir:
        l1_dir = path.abspath(path.join(preprocessing_dir, "..", "..", "l1"))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = preprocessing_dir
    datafind.inputs.match_regex = '.+/sub-(?P<sub>.+)/ses-(?P<ses>.+)/func/.*?_trial-(?P<scan>.+)\.nii.gz'
    datafind_res = datafind.run()
    iterfields = zip(*[
        datafind_res.outputs.sub, datafind_res.outputs.ses,
        datafind_res.outputs.scan
    ])

    if include:
        iterfields = iterfield_selector(iterfields, include, "include")
    if exclude:
        iterfields = iterfield_selector(iterfields, exclude, "exclude")

    infosource = pe.Node(
        interface=util.IdentityInterface(fields=['subject_session_scan']),
        name="infosource")
    infosource.iterables = [('subject_session_scan', iterfields)]

    datafile_source = pe.Node(
        name='datafile_source',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['out_file']))
    datafile_source.inputs.base_directory = preprocessing_dir
    datafile_source.inputs.source_format = "sub-{0}/ses-{1}/func/sub-{0}_ses-{1}_trial-{2}.nii.gz"

    eventfile_source = pe.Node(
        name='eventfile_source',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['out_file']))
    eventfile_source.inputs.base_directory = preprocessing_dir
    eventfile_source.inputs.source_format = "sub-{0}/ses-{1}/func/sub-{0}_ses-{1}_trial-{2}_events.tsv"

    specify_model = pe.Node(interface=SpecifyModel(), name="specify_model")
    specify_model.inputs.input_units = 'secs'
    specify_model.inputs.time_repetition = tr
    specify_model.inputs.high_pass_filter_cutoff = highpass_sigma
    specify_model.inputs.one_condition_file = not per_stimulus_contrast
    specify_model.inputs.habituation_regressor = bool(habituation)

    level1design = pe.Node(interface=Level1Design(), name="level1design")
    level1design.inputs.interscan_interval = tr
    level1design.inputs.bases = {
        "custom": {
            "bfcustompath": "/mnt/data/ni_data/irfs/chr_beta1.txt"
        }
    }
    # level1design.inputs.bases = {'gamma': {'derivs':False, 'gammasigma':10, 'gammadelay':5}}
    level1design.inputs.orthogonalization = {
        1: {
            0: 0,
            1: 0,
            2: 0
        },
        2: {
            0: 1,
            1: 1,
            2: 0
        }
    }
    level1design.inputs.model_serial_correlations = True
    if per_stimulus_contrast:
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0", "e1", "e2", "e3", "e4",
                              "e5"], [1, 1, 1, 1, 1, 1])
        ]  #condition names as defined in specify_model
    elif habituation == "separate_contrast":
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0"], [1]), ('allStim', 'T', ["e1"], [1])
        ]  #condition names as defined in specify_model
    elif habituation == "in_main_contrast":
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0", "e1"], [1, 1])
        ]  #condition names as defined in specify_model
    elif habituation == "confound":
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0"], [1])
        ]  #condition names as defined in specify_model
    else:
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0"], [1])
        ]  #condition names as defined in specify_model

    modelgen = pe.Node(interface=fsl.FEATModel(), name='modelgen')

    glm = pe.Node(interface=fsl.GLM(), name='glm', iterfield='design')
    glm.inputs.out_cope = "cope.nii.gz"
    glm.inputs.out_varcb_name = "varcb.nii.gz"
    #not setting a betas output file might lead to beta export in lieu of COPEs
    glm.inputs.out_file = "betas.nii.gz"
    glm.inputs.out_t_name = "t_stat.nii.gz"
    glm.inputs.out_p_name = "p_stat.nii.gz"
    if mask:
        glm.inputs.mask = mask

    cope_filename = pe.Node(
        name='cope_filename',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['filename']))
    cope_filename.inputs.source_format = "sub-{0}_ses-{1}_trial-{2}_cope.nii.gz"
    varcb_filename = pe.Node(
        name='varcb_filename',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['filename']))
    varcb_filename.inputs.source_format = "sub-{0}_ses-{1}_trial-{2}_varcb.nii.gz"
    tstat_filename = pe.Node(
        name='tstat_filename',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['filename']))
    tstat_filename.inputs.source_format = "sub-{0}_ses-{1}_trial-{2}_tstat.nii.gz"
    zstat_filename = pe.Node(
        name='zstat_filename',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['filename']))
    zstat_filename.inputs.source_format = "sub-{0}_ses-{1}_trial-{2}_zstat.nii.gz"
    pstat_filename = pe.Node(
        name='pstat_filename',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['filename']))
    pstat_filename.inputs.source_format = "sub-{0}_ses-{1}_trial-{2}_pstat.nii.gz"
    pfstat_filename = pe.Node(
        name='pfstat_filename',
        interface=util.Function(
            function=sss_to_source,
            input_names=inspect.getargspec(sss_to_source)[0],
            output_names=['filename']))
    pfstat_filename.inputs.source_format = "sub-{0}_ses-{1}_trial-{2}_pfstat.nii.gz"

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.join(l1_dir, workflow_name)
    datasink.inputs.parameterization = False

    workflow_connections = [
        (infosource, datafile_source, [('subject_session_scan',
                                        'subject_session_scan')]),
        (infosource, eventfile_source, [('subject_session_scan',
                                         'subject_session_scan')]),
        (eventfile_source, specify_model, [('out_file', 'event_files')]),
        (datafile_source, specify_model, [('out_file', 'functional_runs')]),
        (specify_model, level1design, [('session_info', 'session_info')]),
        (level1design, modelgen, [('ev_files', 'ev_files')]),
        (level1design, modelgen, [('fsf_files', 'fsf_file')]),
        (datafile_source, glm, [('out_file', 'in_file')]),
        (modelgen, glm, [('design_file', 'design')]),
        (modelgen, glm, [('con_file', 'contrasts')]),
        (infosource, datasink, [(('subject_session_scan', ss_to_path),
                                 'container')]),
        (infosource, cope_filename, [('subject_session_scan',
                                      'subject_session_scan')]),
        (infosource, varcb_filename, [('subject_session_scan',
                                       'subject_session_scan')]),
        (infosource, tstat_filename, [('subject_session_scan',
                                       'subject_session_scan')]),
        (infosource, zstat_filename, [('subject_session_scan',
                                       'subject_session_scan')]),
        (infosource, pstat_filename, [('subject_session_scan',
                                       'subject_session_scan')]),
        (infosource, pfstat_filename, [('subject_session_scan',
                                        'subject_session_scan')]),
        (cope_filename, glm, [('filename', 'out_cope')]),
        (varcb_filename, glm, [('filename', 'out_varcb_name')]),
        (tstat_filename, glm, [('filename', 'out_t_name')]),
        (zstat_filename, glm, [('filename', 'out_z_name')]),
        (pstat_filename, glm, [('filename', 'out_p_name')]),
        (pfstat_filename, glm, [('filename', 'out_pf_name')]),
        (glm, datasink, [('out_pf', '@pfstat')]),
        (glm, datasink, [('out_p', '@pstat')]),
        (glm, datasink, [('out_z', '@zstat')]),
        (glm, datasink, [('out_t', '@tstat')]),
        (glm, datasink, [('out_cope', '@cope')]),
        (glm, datasink, [('out_varcb', '@varcb')]),
    ]

    workdir_name = workflow_name + "_work"
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.base_dir = l1_dir
    workflow.config = {
        "execution": {
            "crashdump_dir": path.join(l1_dir, "crashdump")
        }
    }
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})
    if not keep_work:
        shutil.rmtree(path.join(l1_dir, workdir_name))
Пример #9
0
def l2_anova(
    l1_dir,
    keep_work=False,
    l2_dir="",
    loud=False,
    tr=1,
    nprocs=6,
    workflow_name="generic",
    mask="/usr/share/mouse-brain-atlases/dsurqec_200micron_mask.nii",
    exclude={},
    include={},
    match_regex='.+/sub-(?P<sub>[a-zA-Z0-9]+)/ses-(?P<ses>[a-zA-Z0-9]+)/.*?_acq-(?P<acq>[a-zA-Z0-9]+)_task-(?P<task>[a-zA-Z0-9]+)_(?P<mod>[a-zA-Z0-9]+)_(?P<stat>(cope|varcb)+)\.(?:nii|nii\.gz)'
):

    l1_dir = path.expanduser(l1_dir)
    if not l2_dir:
        l2_dir = path.abspath(path.join(l1_dir, "..", "..", "l2"))

    mask = path.abspath(path.expanduser(mask))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = l1_dir
    datafind.inputs.match_regex = match_regex
    datafind_res = datafind.run()

    data_selection = zip(*[
        datafind_res.outputs.sub, datafind_res.outputs.ses, datafind_res.
        outputs.acq, datafind_res.outputs.task, datafind_res.outputs.mod,
        datafind_res.outputs.stat, datafind_res.outputs.out_paths
    ])
    data_selection = [list(i) for i in data_selection]
    data_selection = pd.DataFrame(data_selection,
                                  columns=('subject', 'session', 'acquisition',
                                           'task', 'modality', 'statistic',
                                           'path'))

    data_selection = data_selection.sort_values(['session', 'subject'],
                                                ascending=[1, 1])
    if exclude:
        for key in exclude:
            data_selection = data_selection[~data_selection[key].
                                            isin(exclude[key])]
    if include:
        for key in include:
            data_selection = data_selection[data_selection[key].isin(
                include[key])]

    copes = data_selection[data_selection['statistic'] ==
                           'cope']['path'].tolist()
    varcopes = data_selection[data_selection['statistic'] ==
                              'varcb']['path'].tolist()

    copemerge = pe.Node(interface=fsl.Merge(dimension='t'), name="copemerge")
    copemerge.inputs.in_files = copes
    copemerge.inputs.merged_file = 'copes.nii.gz'

    varcopemerge = pe.Node(interface=fsl.Merge(dimension='t'),
                           name="varcopemerge")
    varcopemerge.inputs.in_files = varcopes
    varcopemerge.inputs.merged_file = 'varcopes.nii.gz'

    copeonly = data_selection[data_selection['statistic'] == 'cope']
    regressors = {}
    for sub in copeonly['subject'].unique():
        #print(sub)
        regressor = [copeonly['subject'] == sub][0]
        regressor = [int(i) for i in regressor]
        key = "sub-" + str(sub)
        regressors[key] = regressor
    reference = str(copeonly['session'].unique()[0])
    for ses in copeonly['session'].unique()[1:]:
        #print(ses)
        regressor = [copeonly['session'] == ses][0]
        regressor = [int(i) for i in regressor]
        key = "ses-(" + str(ses) + '-' + reference + ')'
        regressors[key] = regressor

    sessions = [[i, 'T', [i], [1]] for i in regressors.keys() if "ses-" in i]
    contrasts = deepcopy(sessions)
    contrasts.append(['anova', 'F', sessions])

    level2model = pe.Node(interface=fsl.MultipleRegressDesign(),
                          name='level2model')
    level2model.inputs.regressors = regressors
    level2model.inputs.contrasts = contrasts
    #print(regressors)
    #print(contrasts)
    #return

    flameo = pe.Node(interface=fsl.FLAMEO(), name="flameo")
    flameo.inputs.mask_file = mask
    # Using 'fe' instead of 'ols' is recommended (https://dpaniukov.github.io/2016/07/14/three-level-analysis-with-fsl-and-ants-2.html)
    # This has also been tested in SAMRI and shown to give better estimates.
    flameo.inputs.run_mode = "flame12"

    substitutions = []
    t_counter = 1
    f_counter = 1
    for contrast in contrasts:
        if contrast[1] == 'T':
            for i in ['cope', 'tstat', 'zstat']:
                substitutions.append(
                    (i + str(t_counter), contrast[0] + "_" + i))
            t_counter += 1
        if contrast[1] == 'F':
            for i in ['zfstat', 'fstat']:
                substitutions.append(
                    (i + str(f_counter), contrast[0] + "_" + i))
            f_counter += 1

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.join(l2_dir, workflow_name)
    datasink.inputs.substitutions = substitutions

    workflow_connections = [
        (copemerge, flameo, [('merged_file', 'cope_file')]),
        (varcopemerge, flameo, [('merged_file', 'var_cope_file')]),
        (level2model, flameo, [('design_mat', 'design_file')]),
        (level2model, flameo, [('design_grp', 'cov_split_file')]),
        (level2model, flameo, [('design_fts', 'f_con_file')]),
        (level2model, flameo, [('design_con', 't_con_file')]),
        (flameo, datasink, [('copes', '@copes')]),
        (flameo, datasink, [('tstats', '@tstats')]),
        (flameo, datasink, [('zstats', '@zstats')]),
        (flameo, datasink, [('fstats', '@fstats')]),
        (flameo, datasink, [('zfstats', '@zfstats')]),
    ]

    workdir_name = workflow_name + "_work"
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.config = {
        "execution": {
            "crashdump_dir": path.join(l2_dir, "crashdump")
        }
    }
    workflow.base_dir = l2_dir
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    if not loud:
        try:
            workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})
        except RuntimeError:
            print(
                "WARNING: Some expected tasks have not been found (or another RuntimeError has occured)."
            )
        for f in listdir(getcwd()):
            if re.search("crash.*?-varcopemerge|-copemerge.*", f):
                remove(path.join(getcwd(), f))
    else:
        workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})

    if not keep_work:
        shutil.rmtree(path.join(l2_dir, workdir_name))
Пример #10
0
def l2_common_effect(
    l1_dir,
    groupby="session",
    keep_work=False,
    l2_dir="",
    loud=False,
    tr=1,
    nprocs=6,
    workflow_name="generic",
    mask="~/ni_data/templates/ds_QBI_chr_bin.nii.gz",
    subjects=[],
    sessions=[],
    tasks=[],
    exclude={},
    include={},
):

    l1_dir = path.expanduser(l1_dir)
    if not l2_dir:
        l2_dir = path.abspath(path.join(l1_dir, "..", "..", "l2"))

    mask = path.abspath(path.expanduser(mask))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = l1_dir
    datafind.inputs.match_regex = '.+/sub-(?P<sub>[a-zA-Z0-9]+)/ses-(?P<ses>[a-zA-Z0-9]+)/.*?_acq-(?P<acq>[a-zA-Z0-9]+)_task-(?P<task>[a-zA-Z0-9]+)_(?P<mod>[a-zA-Z0-9]+)_(?P<stat>[a-zA-Z0-9]+)\.(?:tsv|nii|nii\.gz)'
    datafind_res = datafind.run()
    data_selection = zip(*[
        datafind_res.outputs.sub, datafind_res.outputs.ses, datafind_res.
        outputs.acq, datafind_res.outputs.task, datafind_res.outputs.mod,
        datafind_res.outputs.stat, datafind_res.outputs.out_paths
    ])
    data_selection = [list(i) for i in data_selection]
    data_selection = pd.DataFrame(data_selection,
                                  columns=('subject', 'session', 'acquisition',
                                           'task', 'modality', 'statistic',
                                           'path'))
    data_selection = data_selection.sort_values(['session', 'subject'],
                                                ascending=[1, 1])
    if exclude:
        for key in exclude:
            data_selection = data_selection[~data_selection[key].
                                            isin(exclude[key])]
    if include:
        for key in include:
            data_selection = data_selection[data_selection[key].isin(
                include[key])]

    copemerge = pe.Node(interface=fsl.Merge(dimension='t'), name="copemerge")
    varcopemerge = pe.Node(interface=fsl.Merge(dimension='t'),
                           name="varcopemerge")

    level2model = pe.Node(interface=fsl.L2Model(), name='level2model')

    flameo = pe.Node(interface=fsl.FLAMEO(), name="flameo")
    flameo.inputs.mask_file = mask
    flameo.inputs.run_mode = "ols"

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.join(l2_dir, workflow_name)
    datasink.inputs.substitutions = [
        ('_iterable_', ''),
    ]

    if groupby == "subject":
        subjects = data_selection[['subject'
                                   ]].drop_duplicates().values.tolist()

        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['iterable']),
            name="infosource")
        infosource.iterables = [('iterable', subjects)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "group",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[['group', 'group']],
                                               varcbs=[['group', 'group']])
        datasource.inputs.field_template = dict(
            copes="sub-%s/ses-*/sub-%s_ses-*_task-*_cope.nii.gz",
            varcbs="sub-%s/ses-*/sub-%s_ses-*_task-*_varcb.nii.gz",
        )
        workflow_connections = [
            (infosource, datasource, [('iterable', 'group')]),
            (infosource, copemerge, [(('iterable', add_suffix, "_cope.nii.gz"),
                                      'merged_file')]),
            (infosource, varcopemerge, [(('iterable', add_suffix,
                                          "_varcb.nii.gz"), 'merged_file')]),
        ]
    elif groupby == "subject_task":
        #does not currently work, due to missing iterator combinations (same issue as preprocessing)
        merge = pe.Node(interface=util.Merge(2), name="merge")
        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['subject', 'task']),
            name="infosource")
        infosource.iterables = [('subject', subjects), ('task', tasks)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "subject",
                "task",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[[
            "subject",
            "subject",
            "task",
        ]],
                                               varcbs=[[
                                                   "subject",
                                                   "subject",
                                                   "task",
                                               ]])
        datasource.inputs.field_template = dict(
            copes="sub-%s/ses-*/sub-%s_ses-*_task-%s_cope.nii.gz",
            varcbs="sub-%s/ses-*/sub-%s_ses-*_task-%s_varcb.nii.gz",
        )
        workflow_connections = [
            (infosource, datasource, [('subject', 'subject'),
                                      ('task', 'task')]),
            (infosource, merge, [('subject', 'in1'), ('task', 'in2')]),
            (merge, copemerge, [(('out', add_suffix, "_cope.nii.gz"),
                                 'merged_file')]),
            (merge, varcopemerge, [(('out', add_suffix, "_varcb.nii.gz"),
                                    'merged_file')]),
        ]
    elif groupby == "session":
        sessions = data_selection[['session']].drop_duplicates()
        sessions = sessions.T.to_dict().values()

        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['iterable']),
            name="infosource")
        infosource.iterables = [('iterable', sessions)]

        copes = pe.Node(
            name='copes',
            interface=util.Function(
                function=select_from_datafind_df,
                input_names=inspect.getargspec(select_from_datafind_df)[0],
                output_names=['selection']))
        copes.inputs.bids_dictionary_override = {'statistic': 'cope'}
        copes.inputs.df = data_selection
        copes.inputs.list_output = True

        varcopes = pe.Node(
            name='varcopes',
            interface=util.Function(
                function=select_from_datafind_df,
                input_names=inspect.getargspec(select_from_datafind_df)[0],
                output_names=['selection']))
        varcopes.inputs.bids_dictionary_override = {'statistic': 'varcb'}
        varcopes.inputs.df = data_selection
        varcopes.inputs.list_output = True

        workflow_connections = [
            (infosource, copemerge, [(('iterable', dict_and_suffix, "session",
                                       "_cope.nii.gz"), 'merged_file')]),
            (infosource, varcopemerge, [(('iterable', dict_and_suffix,
                                          "session", "_varcb.nii.gz"),
                                         'merged_file')]),
        ]
    elif groupby == "task":
        infosource = pe.Node(
            interface=util.IdentityInterface(fields=['iterable']),
            name="infosource")
        infosource.iterables = [('iterable', tasks)]
        datasource = pe.Node(interface=nio.DataGrabber(
            infields=[
                "group",
            ], outfields=["copes", "varcbs"]),
                             name="datasource")
        datasource.inputs.template_args = dict(copes=[['group']],
                                               varcbs=[['group']])
        datasource.inputs.field_template = dict(
            copes="sub-*/ses-*/sub-*_ses-*_task-%s_cope.nii.gz ",
            varcbs="sub-*/ses-*/sub-*_ses-*_task-%s_varcb.nii.gz ",
        )
        workflow_connections = [
            (infosource, datasource, [('iterable', 'group')]),
            (infosource, copemerge, [(('iterable', add_suffix, "_cope.nii.gz"),
                                      'merged_file')]),
            (infosource, varcopemerge, [(('iterable', add_suffix,
                                          "_varcb.nii.gz"), 'merged_file')]),
        ]

    workflow_connections.extend([
        (copes, copemerge, [('selection', 'in_files')]),
        (varcopes, varcopemerge, [('selection', 'in_files')]),
        (varcopes, level2model, [(('selection', mylen), 'num_copes')]),
        (copemerge, flameo, [('merged_file', 'cope_file')]),
        (varcopemerge, flameo, [('merged_file', 'var_cope_file')]),
        (level2model, flameo, [('design_mat', 'design_file')]),
        (level2model, flameo, [('design_grp', 'cov_split_file')]),
        (level2model, flameo, [('design_con', 't_con_file')]),
        (flameo, datasink, [('copes', '@copes')]),
        (flameo, datasink, [('fstats', '@fstats')]),
        (flameo, datasink, [('tstats', '@tstats')]),
        (flameo, datasink, [('zstats', '@zstats')]),
    ])

    workdir_name = workflow_name + "_work"
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.config = {
        "execution": {
            "crashdump_dir": path.join(l2_dir, "crashdump")
        }
    }
    workflow.base_dir = l2_dir
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    if not loud:
        try:
            workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})
        except RuntimeError:
            print(
                "WARNING: Some expected tasks have not been found (or another RuntimeError has occured)."
            )
        for f in listdir(getcwd()):
            if re.search("crash.*?-varcopemerge|-copemerge.*", f):
                remove(path.join(getcwd(), f))
    else:
        workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})

    if not keep_work:
        shutil.rmtree(path.join(l2_dir, workdir_name))
Пример #11
0
def seed_fc(
    preprocessing_dir,
    exclude={},
    habituation='confound',
    highpass_sigma=225,
    lowpass_sigma=False,
    include={},
    keep_work=False,
    out_dir="",
    mask="",
    match_regex='sub-(?P<sub>[a-zA-Z0-9]+)/ses-(?P<ses>[a-zA-Z0-9]+)/func/.*?_task-(?P<task>[a-zA-Z0-9]+)_acq-(?P<acq>[a-zA-Z0-9]+)_(?P<mod>[a-zA-Z0-9]+)\.(?:tsv|nii|nii\.gz)',
    nprocs=N_PROCS,
    tr=1,
    workflow_name="generic",
    modality="cbv",
):
    """Calculate subject level seed-based functional connectivity via the `fsl_glm` command.

	Parameters
	----------

	exclude : dict
		A dictionary with any combination of "sessions", "subjects", "tasks" as keys and corresponding identifiers as values.
		If this is specified matching entries will be excluded in the analysis.
	habituation : {"", "confound", "separate_contrast", "in_main_contrast"}, optional
		How the habituation regressor should be handled.
		Anything which evaluates as False (though we recommend "") means no habituation regressor will be introduced.
	highpass_sigma : int, optional
		Highpass threshold (in seconds).
	include : dict
		A dictionary with any combination of "sessions", "subjects", "tasks" as keys and corresponding identifiers as values.
		If this is specified only matching entries will be included in the analysis.
	keep_work : bool, optional
		Whether to keep the work directory (containing all the intermediary workflow steps, as managed by nipypye).
		This is useful for debugging and quality control.
	out_dir : str, optional
		Path to the directory inside which both the working directory and the output directory will be created.
	mask : str, optional
		Path to the brain mask which shall be used to define the brain volume in the analysis.
		This has to point to an existing NIfTI file containing zero and one values only.
	match_regex : str, optional
		Regex matching pattern by which to select input files. Has to contain groups named "sub", "ses", "acq", "task", and "mod".
	n_procs : int, optional
		Maximum number of processes which to simultaneously spawn for the workflow.
		If not explicitly defined, this is automatically calculated from the number of available cores and under the assumption that the workflow will be the main process running for the duration that it is running.
	tr : int, optional
		Repetition time, in seconds.
	workflow_name : str, optional
		Name of the workflow; this will also be the name of the final output directory produced under `out_dir`.
	"""

    preprocessing_dir = path.abspath(path.expanduser(preprocessing_dir))
    if not out_dir:
        out_dir = path.join(bids_base, 'l1')
    else:
        out_dir = path.abspath(path.expanduser(out_dir))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = preprocessing_dir
    datafind.inputs.match_regex = match_regex
    datafind_res = datafind.run()
    out_paths = [
        path.abspath(path.expanduser(i))
        for i in datafind_res.outputs.out_paths
    ]
    data_selection = zip(*[
        datafind_res.outputs.sub, datafind_res.outputs.ses,
        datafind_res.outputs.acq, datafind_res.outputs.task,
        datafind_res.outputs.mod, out_paths
    ])
    data_selection = [list(i) for i in data_selection]
    data_selection = pd.DataFrame(data_selection,
                                  columns=('subject', 'session', 'acquisition',
                                           'task', 'modality', 'path'))
    if exclude:
        for key in exclude:
            data_selection = data_selection[~data_selection[key].
                                            isin(exclude[key])]
    if include:
        for key in include:
            data_selection = data_selection[data_selection[key].isin(
                include[key])]
    bids_dictionary = data_selection[
        data_selection['modality'] ==
        modality].drop_duplicates().T.to_dict().values()

    infosource = pe.Node(
        interface=util.IdentityInterface(fields=['bids_dictionary']),
        name="infosource")
    infosource.iterables = [('bids_dictionary', bids_dictionary)]

    datafile_source = pe.Node(
        name='datafile_source',
        interface=util.Function(
            function=select_from_datafind_df,
            input_names=inspect.getargspec(select_from_datafind_df)[0],
            output_names=['out_file']))
    datafile_source.inputs.bids_dictionary_override = {'modality': modality}
    datafile_source.inputs.df = data_selection

    seed_timecourse = pe.Node(
        name='seed_timecourse',
        interface=util.Function(
            function=select_from_datafind_df,
            input_names=inspect.getargspec(select_from_datafind_df)[0],
            output_names=['out_file']))

    specify_model = pe.Node(interface=SpecifyModel(), name="specify_model")
    specify_model.inputs.input_units = 'secs'
    specify_model.inputs.time_repetition = tr
    specify_model.inputs.high_pass_filter_cutoff = highpass_sigma
    specify_model.inputs.habituation_regressor = bool(habituation)

    level1design = pe.Node(interface=Level1Design(), name="level1design")
    level1design.inputs.interscan_interval = tr
    if bf_path:
        bf_path = path.abspath(path.expanduser(bf_path))
        level1design.inputs.bases = {"custom": {"bfcustompath": bf_path}}
    # level1design.inputs.bases = {'gamma': {'derivs':False, 'gammasigma':10, 'gammadelay':5}}
    level1design.inputs.orthogonalization = {
        1: {
            0: 0,
            1: 0,
            2: 0
        },
        2: {
            0: 1,
            1: 1,
            2: 0
        }
    }
    level1design.inputs.model_serial_correlations = True
    if habituation == "separate_contrast":
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0"], [1]), ('allStim', 'T', ["e1"], [1])
        ]  #condition names as defined in specify_model
    elif habituation == "in_main_contrast":
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0", "e1"], [1, 1])
        ]  #condition names as defined in specify_model
    elif habituation == "confound" or not habituation:
        level1design.inputs.contrasts = [
            ('allStim', 'T', ["e0"], [1])
        ]  #condition names as defined in specify_model
    else:
        raise ValueError(
            'The value you have provided for the `habituation` parameter, namely "{}", is invalid. Please choose one of: {"confound","in_main_contrast","separate_contrast"}'
            .format(habituation))

    modelgen = pe.Node(interface=fsl.FEATModel(), name='modelgen')
    modelgen.inputs.ignore_exception = True

    glm = pe.Node(interface=fsl.GLM(), name='glm', iterfield='design')
    glm.inputs.out_cope = "cope.nii.gz"
    glm.inputs.out_varcb_name = "varcb.nii.gz"
    #not setting a betas output file might lead to beta export in lieu of COPEs
    glm.inputs.out_file = "betas.nii.gz"
    glm.inputs.out_t_name = "t_stat.nii.gz"
    glm.inputs.out_p_name = "p_stat.nii.gz"
    if mask:
        glm.inputs.mask = path.abspath(path.expanduser(mask))
    glm.inputs.ignore_exception = True

    cope_filename = pe.Node(
        name='cope_filename',
        interface=util.Function(
            function=bids_dict_to_source,
            input_names=inspect.getargspec(bids_dict_to_source)[0],
            output_names=['filename']))
    cope_filename.inputs.source_format = "sub-{subject}_ses-{session}_task-{task}_acq-{acquisition}_{modality}_cope.nii.gz"
    varcb_filename = pe.Node(
        name='varcb_filename',
        interface=util.Function(
            function=bids_dict_to_source,
            input_names=inspect.getargspec(bids_dict_to_source)[0],
            output_names=['filename']))
    varcb_filename.inputs.source_format = "sub-{subject}_ses-{session}_task-{task}_acq-{acquisition}_{modality}_varcb.nii.gz"
    tstat_filename = pe.Node(
        name='tstat_filename',
        interface=util.Function(
            function=bids_dict_to_source,
            input_names=inspect.getargspec(bids_dict_to_source)[0],
            output_names=['filename']))
    tstat_filename.inputs.source_format = "sub-{subject}_ses-{session}_task-{task}_acq-{acquisition}_{modality}_tstat.nii.gz"
    zstat_filename = pe.Node(
        name='zstat_filename',
        interface=util.Function(
            function=bids_dict_to_source,
            input_names=inspect.getargspec(bids_dict_to_source)[0],
            output_names=['filename']))
    zstat_filename.inputs.source_format = "sub-{subject}_ses-{session}_task-{task}_acq-{acquisition}_{modality}_zstat.nii.gz"
    pstat_filename = pe.Node(
        name='pstat_filename',
        interface=util.Function(
            function=bids_dict_to_source,
            input_names=inspect.getargspec(bids_dict_to_source)[0],
            output_names=['filename']))
    pstat_filename.inputs.source_format = "sub-{subject}_ses-{session}_task-{task}_acq-{acquisition}_{modality}_pstat.nii.gz"
    pfstat_filename = pe.Node(
        name='pfstat_filename',
        interface=util.Function(
            function=bids_dict_to_source,
            input_names=inspect.getargspec(bids_dict_to_source)[0],
            output_names=['filename']))
    pfstat_filename.inputs.source_format = "sub-{subject}_ses-{session}_task-{task}_acq-{acquisition}_{modality}_pfstat.nii.gz"

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.join(out_dir, workflow_name)
    datasink.inputs.parameterization = False

    workflow_connections = [
        (infosource, datafile_source, [('bids_dictionary', 'bids_dictionary')
                                       ]),
        (infosource, eventfile_source, [('bids_dictionary', 'bids_dictionary')
                                        ]),
        (eventfile_source, specify_model, [('out_file', 'event_files')]),
        (specify_model, level1design, [('session_info', 'session_info')]),
        (level1design, modelgen, [('ev_files', 'ev_files')]),
        (level1design, modelgen, [('fsf_files', 'fsf_file')]),
        (modelgen, glm, [('design_file', 'design')]),
        (modelgen, glm, [('con_file', 'contrasts')]),
        (infosource, datasink, [(('bids_dictionary', bids_dict_to_dir),
                                 'container')]),
        (infosource, cope_filename, [('bids_dictionary', 'bids_dictionary')]),
        (infosource, varcb_filename, [('bids_dictionary', 'bids_dictionary')]),
        (infosource, tstat_filename, [('bids_dictionary', 'bids_dictionary')]),
        (infosource, zstat_filename, [('bids_dictionary', 'bids_dictionary')]),
        (infosource, pstat_filename, [('bids_dictionary', 'bids_dictionary')]),
        (infosource, pfstat_filename, [('bids_dictionary', 'bids_dictionary')
                                       ]),
        (cope_filename, glm, [('filename', 'out_cope')]),
        (varcb_filename, glm, [('filename', 'out_varcb_name')]),
        (tstat_filename, glm, [('filename', 'out_t_name')]),
        (zstat_filename, glm, [('filename', 'out_z_name')]),
        (pstat_filename, glm, [('filename', 'out_p_name')]),
        (pfstat_filename, glm, [('filename', 'out_pf_name')]),
        (glm, datasink, [('out_pf', '@pfstat')]),
        (glm, datasink, [('out_p', '@pstat')]),
        (glm, datasink, [('out_z', '@zstat')]),
        (glm, datasink, [('out_t', '@tstat')]),
        (glm, datasink, [('out_cope', '@cope')]),
        (glm, datasink, [('out_varcb', '@varcb')]),
    ]

    if highpass_sigma or lowpass_sigma:
        bandpass = pe.Node(interface=fsl.maths.TemporalFilter(),
                           name="bandpass")
        bandpass.inputs.highpass_sigma = highpass_sigma
        if lowpass_sigma:
            bandpass.inputs.lowpass_sigma = lowpass_sigma
        else:
            bandpass.inputs.lowpass_sigma = tr
        workflow_connections.extend([
            (datafile_source, bandpass, [('out_file', 'in_file')]),
            (bandpass, specify_model, [('out_file', 'functional_runs')]),
            (bandpass, glm, [('out_file', 'in_file')]),
        ])
    else:
        workflow_connections.extend([
            (datafile_source, specify_model, [('out_file', 'functional_runs')
                                              ]),
            (datafile_source, glm, [('out_file', 'in_file')]),
        ])

    workdir_name = workflow_name + "_work"
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.base_dir = out_dir
    workflow.config = {
        "execution": {
            "crashdump_dir": path.join(out_dir, "crashdump")
        }
    }
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    workflow.run(plugin="MultiProc", plugin_args={'n_procs': nprocs})
    if not keep_work:
        shutil.rmtree(path.join(out_dir, workdir_name))
Пример #12
0
def diagnose(
    bids_base,
    components=None,
    debug=False,
    exclude={},
    include={},
    keep_crashdump=False,
    keep_work=False,
    match_regex='.+/sub-(?P<sub>[a-zA-Z0-9]+)/ses-(?P<ses>[a-zA-Z0-9]+)/.*?_task-(?P<task>[a-zA-Z0-9]+)_acq-(?P<acq>[a-zA-Z0-9]+)_run-(?P<run>[a-zA-Z0-9]+)_(?P<mod>[a-zA-Z0-9]+).(?:nii|nii\.gz)',
    n_procs=N_PROCS,
    realign="time",
    tr=None,
    workflow_name="diagnostic",
):
    '''Run a basic independent component analysis diagnotic (using FSL's MELODIC) on functional MRI data stored in a BIDS directory tree.

	Parameters
	----------

	bids_base : string, optional
		Path to the top level of a BIDS directory tree for which to perform the diagnostic.
	components : int, optional
		Number of independent components to produce for each functional measurement; if evaluated as False, the number of components is automatically optimized for the given data by FSL's MELODIC.
	debug : bool, optional
		Enable full nipype debugging support for the workflow construction and execution.
	exclude : dict, optional
		A dictionary with any subset of 'subject', 'session', 'acquisition', 'task', 'modality', and 'path' as keys and corresponding identifiers as values.
		This is a blacklist: if this is specified only non-matching entries will be included in the analysis.
	include : dict, optional
		A dictionary with any subset of 'subject', 'session', 'acquisition', 'task', 'modality', and 'path' as keys and corresponding identifiers as values.
		This is a whitelist: if this is specified only matching entries will be included in the analysis.
	keep_crashdump : bool, optional
		Whether to keep the crashdump directory (containing all the crash reports for intermediary workflow steps, as managed by nipypye).
		This is useful for debugging and quality control.
	keep_work : bool, optional
		Whether to keep the work directory (containing all the intermediary workflow steps, as managed by nipypye).
		This is useful for debugging and quality control.
	match_regex : str, optional
		Regex matching pattern by which to select input files. Has to contain groups named "sub", "ses", "acq", "task", and "mod".
	n_procs : int, optional
		Maximum number of processes which to simultaneously spawn for the workflow.
		If not explicitly defined, this is automatically calculated from the number of available cores and under the assumption that the workflow will be the main process running for the duration that it is running.
	realign : {"space","time","spacetime",""}
		Parameter that dictates slictiming correction and realignment of slices. "time" (FSL.SliceTimer) is default, since it works safely. Use others only with caution!
	tr : int, optional
		Repetition time (in seconds); if evaluated as False, the TR will be read from the NIfTI header of each file individually.
	workflow_name : string, optional
		Name of the workflow execution. The output will be saved one level above the bids_base, under a directory bearing the name given here.
	'''

    bids_base = path.abspath(path.expanduser(bids_base))

    datafind = nio.DataFinder()
    datafind.inputs.root_paths = bids_base
    datafind.inputs.match_regex = match_regex
    datafind_res = datafind.run()

    data_selection = zip(*[
        datafind_res.outputs.sub, datafind_res.outputs.ses,
        datafind_res.outputs.acq, datafind_res.outputs.task,
        datafind_res.outputs.mod, datafind_res.outputs.out_paths
    ])
    data_selection = [list(i) for i in data_selection]
    data_selection = pd.DataFrame(data_selection,
                                  columns=('subject', 'session', 'acquisition',
                                           'task', 'modality', 'path'))

    data_selection = data_selection.sort_values(['session', 'subject'],
                                                ascending=[1, 1])
    if exclude:
        for key in exclude:
            data_selection = data_selection[~data_selection[key].
                                            isin(exclude[key])]
    if include:
        for key in include:
            data_selection = data_selection[data_selection[key].isin(
                include[key])]

    data_selection['out_path'] = ''
    if data_selection['path'].str.contains('.nii.gz').any():
        data_selection['out_path'] = data_selection['path'].apply(
            lambda x: path.basename(
                path.splitext(path.splitext(x)[0])[0] + '_MELODIC'))
    else:
        data_selection['out_path'] = data_selection['path'].apply(
            lambda x: path.basename(path.splitext(x)[0] + '_MELODIC'))

    paths = data_selection['path']

    infosource = pe.Node(interface=util.IdentityInterface(
        fields=['path'], mandatory_inputs=False),
                         name="infosource")
    infosource.iterables = [('path', paths)]

    dummy_scans = pe.Node(
        name='dummy_scans',
        interface=util.Function(
            function=force_dummy_scans,
            input_names=inspect.getargspec(force_dummy_scans)[0],
            output_names=['out_file', 'deleted_scans']))
    dummy_scans.inputs.desired_dummy_scans = 10

    bids_filename = pe.Node(name='bids_filename',
                            interface=util.Function(
                                function=out_path,
                                input_names=inspect.getargspec(out_path)[0],
                                output_names=['filename']))
    bids_filename.inputs.selection_df = data_selection

    bids_container = pe.Node(name='path_container',
                             interface=util.Function(
                                 function=container,
                                 input_names=inspect.getargspec(container)[0],
                                 output_names=['container']))
    bids_container.inputs.selection_df = data_selection

    datasink = pe.Node(nio.DataSink(), name='datasink')
    datasink.inputs.base_directory = path.abspath(
        path.join(bids_base, '..', workflow_name))
    datasink.inputs.parameterization = False

    melodic = pe.Node(interface=fsl.model.MELODIC(), name="melodic")
    if tr:
        melodic.inputs.tr_sec = tr
    melodic.inputs.report = True
    if components:
        melodic.inputs.dim = int(components)

    workflow_connections = [
        (infosource, dummy_scans, [('path', 'in_file')]),
        (infosource, bids_filename, [('path', 'in_path')]),
        (bids_filename, bids_container, [('filename', 'out_path')]),
        (bids_filename, melodic, [('filename', 'out_dir')]),
        (bids_container, datasink, [('container', 'container')]),
        (melodic, datasink, [('out_dir', 'func')]),
    ]

    if not tr:
        report_tr = pe.Node(name='report_tr',
                            interface=util.Function(
                                function=get_tr,
                                input_names=inspect.getargspec(get_tr)[0],
                                output_names=['tr']))
        report_tr.inputs.ndim = 4

        workflow_connections.extend([
            (infosource, report_tr, [('path', 'in_file')]),
            (report_tr, melodic, [('tr', 'tr_sec')]),
        ])

    if realign == "space":
        realigner = pe.Node(interface=spm.Realign(), name="realigner")
        realigner.inputs.register_to_mean = True
        workflow_connections.extend([
            (dummy_scans, realigner, [('out_file', 'in_file')]),
            (realigner, melodic, [('out_file', 'in_files')]),
        ])
    elif realign == "spacetime":
        realigner = pe.Node(interface=nipy.SpaceTimeRealigner(),
                            name="realigner")
        realigner.inputs.slice_times = "asc_alt_2"
        if tr:
            realigner.inputs.tr = tr
        else:
            workflow_connections.extend([
                (report_tr, realigner, [('tr', 'tr')]),
            ])
        #3 for coronal slices (2 for horizontal, 1 for sagittal)
        realigner.inputs.slice_info = 3
        workflow_connections.extend([
            (dummy_scans, realigner, [('out_file', 'in_file')]),
            (realigner, melodic, [('out_file', 'in_files')]),
        ])
    elif realign == "time":
        realigner = pe.Node(interface=fsl.SliceTimer(), name="slicetimer")
        if tr:
            realigner.inputs.time_repetition = tr
        else:
            workflow_connections.extend([
                (report_tr, realigner, [('tr', 'time_repetition')]),
            ])
        workflow_connections.extend([
            (dummy_scans, realigner, [('out_file', 'in_file')]),
            (realigner, melodic, [('slice_time_corrected_file', 'in_files')]),
        ])
    else:
        workflow_connections.extend([
            (dummy_scans, melodic, [('out_file', 'in_files')]),
        ])

    crashdump_dir = path.abspath(
        path.join(bids_base, '..', workflow_name + '_crashdump'))
    workflow_config = {'execution': {'crashdump_dir': crashdump_dir}}
    if debug:
        workflow_config['logging'] = {
            'workflow_level': 'DEBUG',
            'utils_level': 'DEBUG',
            'interface_level': 'DEBUG',
            'filemanip_level': 'DEBUG',
            'log_to_file': 'true',
        }

    workdir_name = workflow_name + '_work'
    workflow = pe.Workflow(name=workdir_name)
    workflow.connect(workflow_connections)
    workflow.base_dir = path.abspath(path.join(bids_base, '..'))
    workflow.config = workflow_config
    workflow.write_graph(dotfilename=path.join(workflow.base_dir, workdir_name,
                                               "graph.dot"),
                         graph2use="hierarchical",
                         format="png")

    if not keep_work or not keep_crashdump:
        try:
            workflow.run(plugin="MultiProc", plugin_args={'n_procs': n_procs})
        except RuntimeError:
            pass
    else:
        workflow.run(plugin="MultiProc", plugin_args={'n_procs': n_procs})
    if not keep_work:
        shutil.rmtree(path.join(workflow.base_dir, workdir_name))
    if not keep_crashdump:
        try:
            shutil.rmtree(crashdump_dir)
        except (FileNotFoundError, OSError):
            pass

    return