def estimate_smoothness(self, overwrite=None, imgtype='zstat'): """ estimate smoothness of Z maps using FSL's smoothness estimation """ log_to_file( self.dirs.logfile, sys._getframe().f_code.co_name, headspace=2) func_args = inspect.getargvalues( inspect.currentframe()).locals log_to_file( self.dirs.logfile, stringify_dict(func_args)) if overwrite is None: overwrite = self.overwrite output_file = os.path.join(self.dirs.dirs['metadata'], 'smoothness_est.csv') if os.path.exists(output_file) and not overwrite: if self.verbose: print('using existing smoothness file') smoothness_df = pandas.read_csv(output_file) return(smoothness_df) # use nipype's interface to the FSL smoothest command est = SmoothEstimate() smoothness = [] for teamID in self.complete_image_sets['unthresh']: for hyp in range(1, 10): if hyp not in self.teams[teamID].images['unthresh'][imgtype]: # fill missing data with nan print('no zstat present for', teamID, hyp) smoothness.append([teamID, hyp, numpy.nan, numpy.nan, numpy.nan]) continue infile = self.teams[teamID].images['unthresh'][imgtype][hyp] if not os.path.exists(infile): print('no image present:', infile) continue else: if self.verbose: print('estimating smoothness for hyp', hyp) est.inputs.zstat_file = infile est.inputs.mask_file = self.dirs.MNI_mask est.terminal_output = 'file_split' smoothest_output = est.run() smoothness.append([teamID, hyp, smoothest_output.outputs.dlh, smoothest_output.outputs.volume, smoothest_output.outputs.resels]) self.teams[teamID].logs['smoothest'] = ( smoothest_output.runtime.stdout, smoothest_output.runtime.stderr) smoothness_df = pandas.DataFrame( smoothness, columns=['teamID', 'hyp', 'dhl', 'volume', 'resels']) smoothness_df.to_csv(output_file) return(smoothness_df)
def test_SmoothEstimate_inputs(): input_map = dict(ignore_exception=dict(nohash=True, usedefault=True, ), residual_fit_file=dict(requires=['dof'], argstr='--res=%s', ), args=dict(argstr='%s', ), dof=dict(mandatory=True, argstr='--dof=%d', xor=['zstat_file'], ), terminal_output=dict(mandatory=True, nohash=True, ), environ=dict(nohash=True, usedefault=True, ), zstat_file=dict(xor=['dof'], argstr='--zstat=%s', ), mask_file=dict(mandatory=True, argstr='--mask=%s', ), output_type=dict(), ) inputs = SmoothEstimate.input_spec() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(inputs.traits()[key], metakey), value
def test_SmoothEstimate_outputs(): output_map = dict(volume=dict(), resels=dict(), dlh=dict(), ) outputs = SmoothEstimate.output_spec() for key, metadata in output_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(outputs.traits()[key], metakey), value
def test_SmoothEstimate_outputs(): output_map = dict( dlh=dict(), resels=dict(), volume=dict(), ) outputs = SmoothEstimate.output_spec() for key, metadata in output_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(outputs.traits()[key], metakey), value
def test_SmoothEstimate_inputs(): input_map = dict( args=dict(argstr='%s', ), dof=dict( argstr='--dof=%d', mandatory=True, xor=['zstat_file'], ), environ=dict( nohash=True, usedefault=True, ), ignore_exception=dict( nohash=True, usedefault=True, ), mask_file=dict( argstr='--mask=%s', mandatory=True, ), output_type=dict(), residual_fit_file=dict( argstr='--res=%s', requires=['dof'], ), terminal_output=dict( mandatory=True, nohash=True, ), zstat_file=dict( argstr='--zstat=%s', xor=['dof'], ), ) inputs = SmoothEstimate.input_spec() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(inputs.traits()[key], metakey), value
def rs_grouplevel(copes, varcopes, dofs, output_dir, work_dir): from nipype.interfaces.fsl.model import MultipleRegressDesign from nipype.interfaces.utility import Function from nipype.interfaces.fsl.model import FLAMEO from nipype.interfaces.fsl.model import SmoothEstimate from connectivity.interfaces import Cluster from nipype.interfaces.fsl.utils import Merge from nipype.interfaces.fsl import Info from connectivity.interfaces import PtoZ grplevelworkflow = pe.Workflow(name="grplevelworkflow") grplevelworkflow.base_dir = work_dir merger = Merge() merger.inputs.dimension = 't' merger.inputs.in_files = copes merger.inputs.merged_file = op.join(work_dir, 'cope.nii.gz') merger.run() merger.inputs.in_files = varcopes merger.inputs.merged_file = op.join(work_dir, 'varcope.nii.gz') merger.run() merger.inputs.in_files = dofs merger.inputs.merged_file = op.join(work_dir, 'dof.nii.gz') merger.run() model = pe.Node(interface=MultipleRegressDesign(), name='model') model.inputs.contrasts = [['mean', 'T', ['roi'], [1]]] model.inputs.regressors = dict(roi=np.ones(len(copes)).tolist()) flameo = pe.Node(interface=FLAMEO(), name='flameo') flameo.inputs.cope_file = op.join(work_dir, 'cope.nii.gz') flameo.inputs.var_cope_file = op.join(work_dir, 'varcope.nii.gz') flameo.inputs.dof_var_cope_file = op.join(work_dir, 'dof.nii.gz') flameo.inputs.run_mode = 'flame1' flameo.inputs.mask_file = Info.standard_image( 'MNI152_T1_2mm_brain_mask.nii.gz') grplevelworkflow.connect(model, 'design_con', flameo, 't_con_file') grplevelworkflow.connect(model, 'design_grp', flameo, 'cov_split_file') grplevelworkflow.connect(model, 'design_mat', flameo, 'design_file') smoothest = pe.Node(SmoothEstimate(), name='smooth_estimate') grplevelworkflow.connect(flameo, 'zstats', smoothest, 'residual_fit_file') smoothest.inputs.mask_file = Info.standard_image( 'MNI152_T1_2mm_brain_mask.nii.gz') smoothest.inputs.dof = len(dofs) - 1 cluster = pe.Node(Cluster(), name='cluster') ptoz = pe.Node(PtoZ(), name='ptoz') ptoz.inputs.pvalue = 0.001 calculate_resels = pe.Node(Function(input_names=["volume", "resels"], output_names=["resels"], function=calcres), name="calcres") grplevelworkflow.connect(smoothest, 'resels', cluster, 'resels') grplevelworkflow.connect(smoothest, 'resels', calculate_resels, 'resels') grplevelworkflow.connect(smoothest, 'volume', calculate_resels, 'volume') grplevelworkflow.connect(calculate_resels, 'resels', ptoz, 'resels') grplevelworkflow.connect(ptoz, 'zstat', cluster, 'threshold') cluster.inputs.connectivity = 26 cluster.inputs.out_threshold_file = True cluster.inputs.out_index_file = True cluster.inputs.out_localmax_txt_file = True cluster.inputs.voxthresh = True grplevelworkflow.connect(flameo, 'zstats', cluster, 'in_file') datasink = pe.Node(nio.DataSink(), name='sinker') datasink.inputs.base_directory = work_dir grplevelworkflow.connect(flameo, 'zstats', datasink, 'z') grplevelworkflow.connect(cluster, 'threshold_file', datasink, 'z_thresh') grplevelworkflow.run() shutil.rmtree(op.join(work_dir, 'grplevelworkflow')) #copy data to directory shutil.copyfile(op.join(work_dir, 'z', 'zstat1.nii.gz'), op.join(output_dir, 'z.nii.gz')) shutil.copyfile(op.join(work_dir, 'z_thresh', 'zstat1_threshold.nii.gz'), op.join(output_dir, 'z_level-voxel_corr-FWE.nii.gz')) shutil.rmtree(work_dir)
model = MultipleRegressDesign() model.inputs.contrasts = [['mean', 'T', ['roi'], [1]]] model.intputs.regressors = dict(roi=np.ones(len(copes))) flameo = pe.Node(interface=FLAMEO(), name='flameo') flameo.inputs.cope_file = op.join(work_dir, 'cope.nii.gz') flameo.inputs.var_cope_file = op.join(work_dir, 'varcope.nii.gz') flameo.inputs.run_mode = 'flame1' flameo.inputs.mask = standard_image('MNI152_T1_2mm_brain_mask.nii.gz') grplevelworkflow.connect(model, 'design_con', flameo, 'inputs.t_con_file') grplevelworkflow.connect(model, 'design_grp', flameo, 'inputs.cov_split_file') grplevelworkflow.connect(model, 'design_mat', flameo, 'inputs.design_file') smoothest = Node(SmoothEstimate(), name='smooth_estimate') grplevelworkflow.connect(flameo, 'zstats', smoothest, 'zstat_file') smoothest.inputs.mask_file = mask_file cluster = Node(Cluster(), name='cluster') grplevelworkflow.connect(smoothest, 'resels', cluster, 'resels') grplevelworkflow.connect(smoothest, (['volume', 'resels'], calcres), ptoz, 'resels') grplevelworkflow.connect(ptoz, 'zstat', cluster, 'threshold') cluster.inputs.connectivity = 26 cluster.inputs.out_threshold_file = True cluster.inputs.out_index_file = True cluster.inputs.out_localmax_txt_file = True cluster.inputs.voxthresh = True grplevelworkflow.connect(flame, 'zstats', cluster, 'in_file')
def create_subject_ffx_wf( sub_id, bet_fracthr, spatial_fwhm, susan_brightthresh, hp_vols, lp_vols, remove_hemi, film_thresh, film_model_autocorr, use_derivs, tr, tcon_subtractive, cluster_threshold, cluster_thresh_frac, cluster_p, dilate_clusters_voxel, cond_ids, dsdir, work_basedir): # todo: new mapnode inputs: cluster_threshold, cluster_p """ Make a workflow including preprocessing, first level, and second level GLM analysis for a given subject. This pipeline includes: - skull stripping - spatial smoothing - removing the irrelevant hemisphere - temporal band pass filter - 1st level GLM - averaging f-contrasts from 1st level GLM - clustering run-wise f-tests, dilating clusters, and returning binary roi mask """ from nipype.algorithms.modelgen import SpecifyModel from nipype.interfaces.fsl import BET, SUSAN, ImageMaths from nipype.interfaces.fsl.model import SmoothEstimate, Cluster from nipype.interfaces.fsl.maths import TemporalFilter, MathsCommand from nipype.interfaces.utility import Function from nipype.pipeline.engine import Workflow, Node, MapNode from nipype.workflows.fmri.fsl import create_modelfit_workflow from nipype.interfaces.fsl.maths import MultiImageMaths from nipype.interfaces.utility import IdentityInterface import sys from os.path import join as pjoin import os sys.path.insert( 0, "/data/project/somato/raw/code/roi_glm/custom_node_functions.py") # TODO: don't hardcode this import custom_node_functions # set up sub-workflow sub_wf = Workflow(name='subject_%s_wf' % sub_id) # set up sub-working-directory subwf_wd = pjoin(work_basedir, 'subject_ffx_wfs', 'subject_%s_ffx_workdir' % sub_id) if not os.path.exists(subwf_wd): os.makedirs(subwf_wd) sub_wf.base_dir = subwf_wd # Grab bold files for all four runs of one subject. # in the order [d1_d5, d5_d1, blocked_design1, blocked_design2] grab_boldfiles = Node(Function( function=custom_node_functions.grab_boldfiles_subject, input_names=['sub_id', 'cond_ids', 'ds_dir'], output_names=['boldfiles']), name='grab_boldfiles') grab_boldfiles.inputs.sub_id = sub_id grab_boldfiles.inputs.cond_ids = cond_ids grab_boldfiles.inputs.ds_dir = dsdir getonsets = Node(Function( function=custom_node_functions.grab_blocked_design_onsets_subject, input_names=['sub_id', 'prepped_ds_dir'], output_names=['blocked_design_onsets_dicts']), name='getonsets') getonsets.inputs.sub_id = sub_id getonsets.inputs.prepped_ds_dir = dsdir # pass bold files through preprocessing pipeline bet = MapNode(BET(frac=bet_fracthr, functional=True, mask=True), iterfield=['in_file'], name='bet') pick_mask = Node(Function(function=custom_node_functions.pick_first_mask, input_names=['mask_files'], output_names=['first_mask']), name='pick_mask') # SUSAN smoothing node susan = MapNode(SUSAN(fwhm=spatial_fwhm, brightness_threshold=susan_brightthresh), iterfield=['in_file'], name='susan') # bandpass filter node bpf = MapNode(TemporalFilter(highpass_sigma=hp_vols / 2.3548, lowpass_sigma=lp_vols / 2.3548), iterfield=['in_file'], name='bpf') # cut away hemisphere node if remove_hemi == 'r': roi_args = '-roi 96 -1 0 -1 0 -1 0 -1' elif remove_hemi == 'l': roi_args = '-roi 0 96 0 -1 0 -1 0 -1' else: raise IOError('did not recognite value of remove_hemi %s' % remove_hemi) cut_hemi_func = MapNode(MathsCommand(), iterfield=['in_file'], name='cut_hemi_func') cut_hemi_func.inputs.args = roi_args cut_hemi_mask = MapNode(MathsCommand(), iterfield=['in_file'], name='cut_hemi_mask') cut_hemi_mask.inputs.args = roi_args # Make Design and Contrasts for that subject # subject_info ist a list of two "Bunches", each for one run, containing conditions, onsets, durations designgen = Node(Function( input_names=['subtractive_contrast', 'blocked_design_onsets_dicts'], output_names=['subject_info', 'contrasts'], function=custom_node_functions.make_bunch_and_contrasts), name='designgen') designgen.inputs.subtractive_contrasts = tcon_subtractive # create 'session_info' for modelfit modelspec = MapNode(SpecifyModel(input_units='secs'), name='modelspec', iterfield=['functional_runs', 'subject_info']) modelspec.inputs.high_pass_filter_cutoff = hp_vols * tr modelspec.inputs.time_repetition = tr flatten_session_infos = Node(Function( input_names=['nested_list'], output_names=['flat_list'], function=custom_node_functions.flatten_nested_list), name='flatten_session_infos') # Fist-level workflow modelfit = create_modelfit_workflow(f_contrasts=True) modelfit.inputs.inputspec.interscan_interval = tr modelfit.inputs.inputspec.film_threshold = film_thresh modelfit.inputs.inputspec.model_serial_correlations = film_model_autocorr modelfit.inputs.inputspec.bases = {'dgamma': {'derivs': use_derivs}} # node that reshapes list of copes returned from modelfit cope_sorter = Node(Function(input_names=['copes', 'varcopes', 'contrasts'], output_names=['copes', 'varcopes', 'n_runs'], function=custom_node_functions.sort_copes), name='cope_sorter') # average zfstats from both runs split_zfstats = Node(Function( function=custom_node_functions.split_zfstats_runs, input_names=['zfstats_list'], output_names=['zfstat_run1', 'zfstat_run2']), name='split_zfstats') average_zfstats = Node(MultiImageMaths(op_string='-add %s -div 2'), name='mean_images') # estimate smoothness of 1st lvl zf-files smoothest = MapNode(SmoothEstimate(), name='smoothest', iterfield=['mask_file', 'zstat_file']) cluster = MapNode(Cluster(), name='cluster', iterfield=['in_file', 'volume', 'dlh']) cluster.inputs.threshold = cluster_threshold cluster.inputs.pthreshold = cluster_p cluster.inputs.fractional = cluster_thresh_frac cluster.inputs.no_table = True cluster.inputs.out_threshold_file = True cluster.inputs.out_pval_file = True cluster.inputs.out_localmax_vol_file = True cluster.inputs.out_max_file = True cluster.inputs.out_size_file = True # dilate clusters dilate = MapNode(MathsCommand(args='-kernel sphere %i -dilD' % dilate_clusters_voxel), iterfield=['in_file'], name='dilate') # binarize the result to a mask binarize_roi = MapNode(ImageMaths(op_string='-nan -thr 0.001 -bin'), iterfield=['in_file'], name='binarize_roi') # connect preprocessing sub_wf.connect(grab_boldfiles, 'boldfiles', bet, 'in_file') sub_wf.connect(bet, 'out_file', susan, 'in_file') sub_wf.connect(susan, 'smoothed_file', bpf, 'in_file') sub_wf.connect(bpf, 'out_file', cut_hemi_func, 'in_file') sub_wf.connect(bet, 'mask_file', cut_hemi_mask, 'in_file') # connect to 1st level model sub_wf.connect(cut_hemi_func, 'out_file', modelspec, 'functional_runs') sub_wf.connect(getonsets, 'blocked_design_onsets_dicts', designgen, 'blocked_design_onsets_dicts') sub_wf.connect(designgen, 'subject_info', modelspec, 'subject_info') sub_wf.connect(modelspec, 'session_info', flatten_session_infos, 'nested_list') sub_wf.connect(flatten_session_infos, 'flat_list', modelfit, 'inputspec.session_info') sub_wf.connect(designgen, 'contrasts', modelfit, 'inputspec.contrasts') sub_wf.connect(cut_hemi_func, 'out_file', modelfit, 'inputspec.functional_data') # connect to cluster thresholding sub_wf.connect(cut_hemi_mask, 'out_file', smoothest, 'mask_file') sub_wf.connect(modelfit.get_node('modelestimate'), 'zfstats', smoothest, 'zstat_file') sub_wf.connect(modelfit.get_node('modelestimate'), 'zfstats', cluster, 'in_file') sub_wf.connect(smoothest, 'dlh', cluster, 'dlh') sub_wf.connect(smoothest, 'volume', cluster, 'volume') sub_wf.connect(cluster, 'threshold_file', dilate, 'in_file') sub_wf.connect(dilate, 'out_file', binarize_roi, 'in_file') # connect to averaging f-contrasts sub_wf.connect(modelfit.get_node('modelestimate'), 'zfstats', split_zfstats, 'zfstats_list') sub_wf.connect(split_zfstats, 'zfstat_run1', average_zfstats, 'in_file') sub_wf.connect(split_zfstats, 'zfstat_run2', average_zfstats, 'operand_files') # redirect to outputspec # TODO: redirekt outputspec to datasink in meta-wf outputspec = Node(IdentityInterface(fields=[ 'threshold_file', 'index_file', 'pval_file', 'localmax_txt_file' ]), name='outputspec') sub_wf.connect(cluster, 'threshold_file', outputspec, 'threshold_file') sub_wf.connect(cluster, 'index_file', outputspec, 'index_file') sub_wf.connect(cluster, 'pval_file', outputspec, 'pval_file') sub_wf.connect(cluster, 'localmax_txt_file', outputspec, 'localmax_txt_file') sub_wf.connect(binarize_roi, 'out_file', outputspec, 'roi') # run subject-lvl workflow # sub_wf.write_graph(graph2use='colored', dotfilename='./subwf_graph.dot') # sub_wf.run(plugin='MultiProc', plugin_args={'n_procs': 6}) # sub_wf.run(plugin='CondorDAGMan') # sub_wf.run() return sub_wf