def run_suject_level1_glm( subject_data, readout_time=.01392, # seconds tr=.72, dc=True, hrf_model="Canonical with Derivative", drift_model="Cosine", hfcut=100, regress_motion=True, slicer='ortho', cut_coords=None, threshold=3., cluster_th=15, normalize=True, fwhm=0., protocol="MOTOR", func_write_voxel_sizes=None, anat_write_voxel_sizes=None, **other_preproc_kwargs): """ Function to do preproc + analysis for a single HCP subject (task fMRI) """ add_regs_files = None n_motion_regressions = 6 subject_data.n_sessions = 2 subject_data.tmp_output_dir = os.path.join(subject_data.output_dir, "tmp") if not os.path.exists(subject_data.tmp_output_dir): os.makedirs(subject_data.tmp_output_dir) if not os.path.exists(subject_data.output_dir): os.makedirs(subject_data.output_dir) mem = Memory(os.path.join(subject_data.output_dir, "cache_dir"), verbose=100) # glob design files (.fsf) subject_data.design_files = [ os.path.join(subject_data.data_dir, ("MNINonLinear/Results/tfMRI_%s_%s/" "tfMRI_%s_%s_hp200_s4_level1.fsf") % (protocol, direction, protocol, direction)) for direction in ['LR', 'RL'] ] assert len(subject_data.design_files) == 2 for df in subject_data.design_files: if not os.path.isfile(df): return if 0x0: subject_data = _do_fmri_distortion_correction( subject_data, dc=dc, fwhm=fwhm, readout_time=readout_time, **other_preproc_kwargs) # chronometry stats_start_time = pretty_time() # merged lists paradigms = [] frametimes_list = [] design_matrices = [] # fmri_files = [] n_scans = [] # for direction, direction_index in zip(['LR', 'RL'], xrange(2)): for sess in xrange(subject_data.n_sessions): direction = ['LR', 'RL'][sess] # glob the design file # design_file = os.path.join(# _subject_data_dir, "tfMRI_%s_%s" % ( # protocol, direction), design_file = subject_data.design_files[sess] # "tfMRI_%s_%s_hp200_s4_level1.fsf" % ( # protocol, direction)) if not os.path.isfile(design_file): print "Can't find design file %s; skipping subject %s" % ( design_file, subject_data.subject_id) return # read the experimental setup print "Reading experimental setup from %s ..." % design_file fsl_condition_ids, timing_files, fsl_contrast_ids, contrast_values = \ read_fsl_design_file(design_file) print "... done.\r\n" # fix timing filenames timing_files = [ tf.replace("EVs", "tfMRI_%s_%s/EVs" % (protocol, direction)) for tf in timing_files ] # make design matrix print "Constructing design matrix for direction %s ..." % direction _n_scans = nibabel.load(subject_data.func[sess]).shape[-1] n_scans.append(_n_scans) add_regs_file = add_regs_files[ sess] if not add_regs_files is None else None design_matrix, paradigm, frametimes = make_dmtx_from_timing_files( timing_files, fsl_condition_ids, n_scans=_n_scans, tr=tr, hrf_model=hrf_model, drift_model=drift_model, hfcut=hfcut, add_regs_file=add_regs_file, add_reg_names=[ 'Translation along x axis', 'Translation along yaxis', 'Translation along z axis', 'Rotation along x axis', 'Rotation along y axis', 'Rotation along z axis', 'Differential Translation along x axis', 'Differential Translation along yaxis', 'Differential Translation along z axis', 'Differential Rotation along x axis', 'Differential Rotation along y axis', 'Differential Rotation along z axis' ][:n_motion_regressions] if not add_regs_files is None else None, ) print "... done." paradigms.append(paradigm) frametimes_list.append(frametimes) design_matrices.append(design_matrix) # convert contrasts to dict contrasts = dict(( contrast_id, # append zeros to end of contrast to match design np.hstack(( contrast_value, np.zeros(len(design_matrix.names) - len(contrast_value))))) for contrast_id, contrast_value in zip( fsl_contrast_ids, contrast_values)) # more interesting contrasts if protocol == 'MOTOR': contrasts['RH-LH'] = contrasts['RH'] - contrasts['LH'] contrasts['LH-RH'] = -contrasts['RH-LH'] contrasts['RF-LF'] = contrasts['RF'] - contrasts['LF'] contrasts['LF-RF'] = -contrasts['RF-LF'] contrasts['H'] = contrasts['RH'] + contrasts['LH'] contrasts['F'] = contrasts['RF'] + contrasts['LF'] contrasts['H-F'] = contrasts['RH'] + contrasts['LH'] - ( contrasts['RF'] - contrasts['LF']) contrasts['F-H'] = -contrasts['H-F'] contrasts = dict((k, v) for k, v in contrasts.iteritems() if "-" in k) # replicate contrasts across sessions contrasts = dict((cid, [cval] * 2) for cid, cval in contrasts.iteritems()) cache_dir = cache_dir = os.path.join(subject_data.output_dir, 'cache_dir') if not os.path.exists(cache_dir): os.makedirs(cache_dir) nipype_mem = NipypeMemory(base_dir=cache_dir) if 0x0: if np.sum(fwhm) > 0.: subject_data.func = nipype_mem.cache(spm.Smooth)( in_files=subject_data.func, fwhm=fwhm, ignore_exception=False, ).outputs.smoothed_files # fit GLM def tortoise(*args): print args print( 'Fitting a "Fixed Effect" GLM for merging LR and RL ' 'phase-encoding directions for subject %s ...' % (subject_data.subject_id)) fmri_glm = FMRILinearModel( subject_data.func, [design_matrix.matrix for design_matrix in design_matrices], mask='compute') fmri_glm.fit(do_scaling=True, model='ar1') print "... done.\r\n" # save computed mask mask_path = os.path.join(subject_data.output_dir, "mask.nii") print "Saving mask image to %s ..." % mask_path nibabel.save(fmri_glm.mask, mask_path) print "... done.\r\n" z_maps = {} effects_maps = {} map_dirs = {} try: for contrast_id, contrast_val in contrasts.iteritems(): print "\tcontrast id: %s" % contrast_id z_map, eff_map = fmri_glm.contrast(contrast_val, con_id=contrast_id, output_z=True, output_effects=True) # store stat maps to disk for map_type, out_map in zip(['z', 'effects'], [z_map, eff_map]): map_dir = os.path.join(subject_data.output_dir, '%s_maps' % map_type) map_dirs[map_type] = map_dir if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join( map_dir, '%s_%s.nii' % (map_type, contrast_id)) print "\t\tWriting %s ..." % map_path nibabel.save(out_map, map_path) # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path return effects_maps, z_maps, mask_path, map_dirs except: return None # compute native-space maps and mask stuff = mem.cache(tortoise)(subject_data.func, subject_data.anat) if stuff is None: return None effects_maps, z_maps, mask_path, map_dirs = stuff # remove repeated contrasts contrasts = dict((cid, cval[0]) for cid, cval in contrasts.iteritems()) import json json.dump( dict((k, list(v)) for k, v in contrasts.iteritems()), open(os.path.join(subject_data.tmp_output_dir, "contrasts.json"), "w")) subject_data.contrasts = contrasts if normalize: assert hasattr(subject_data, "parameter_file") subject_data.native_effects_maps = effects_maps subject_data.native_z_maps = z_maps subject_data.native_mask_path = mask_path # warp effects maps and mask from native to standard space (MNI) apply_to_files = [ v for _, v in subject_data.native_effects_maps.iteritems() ] + [subject_data.native_mask_path] tmp = nipype_mem.cache(spm.Normalize)( parameter_file=getattr(subject_data, "parameter_file"), apply_to_files=apply_to_files, write_bounding_box=[[-78, -112, -50], [78, 76, 85]], write_voxel_sizes=func_write_voxel_sizes, write_wrap=[0, 0, 0], write_interp=1, jobtype='write', ignore_exception=False, ).outputs.normalized_files subject_data.mask = hard_link(tmp[-1], subject_data.output_dir) subject_data.effects_maps = dict( zip(effects_maps.keys(), hard_link(tmp[:-1], map_dirs["effects"]))) # warp anat image subject_data.anat = hard_link( nipype_mem.cache(spm.Normalize)( parameter_file=getattr(subject_data, "parameter_file"), apply_to_files=subject_data.anat, write_bounding_box=[[-78, -112, -50], [78, 76, 85]], write_voxel_sizes=anat_write_voxel_sizes, write_wrap=[0, 0, 0], write_interp=1, jobtype='write', ignore_exception=False, ).outputs.normalized_files, subject_data.anat_output_dir) else: subject_data.mask = mask_path subject_data.effects_maps = effects_maps subject_data.z_maps = z_maps return subject_data
def do_glm_for_subject(subject_id, bold_base_folder, trial_base_folder, output_base_folder): subject_dir = path(bold_base_folder) / ("sub%03d" % subject_id) output_dir = (path(output_base_folder) / ("sub%03d" % subject_id) / "model001") print output_dir if not output_dir.exists(): output_dir.makedirs() anat_file = subject_dir / "highres001.nii" anat = nb.load(anat_file) run_ids = range(1, 10) task_bold_files = [subject_dir.glob("task001_run%03d/rbold*.nii" % rid)[0] for rid in run_ids] task_mvt_files = [subject_dir.glob("task001_run%03d/rp_bold*.txt" % rid)[0] for rid in run_ids] trial_files = [(path(trial_base_folder) / ("Sub%02d" % subject_id) / "BOLD" / "Trials" / ("run_%02d_spmdef.txt" % rid)) for rid in range(1, 10)] stats_start_time = pretty_time() paradigms = [] design_matrices = [] n_scans = [] all_frametimes = [] list_of_contrast_dicts = [] # one dict per run for bold_file, mvt_file, trial_file in zip(task_bold_files, task_mvt_files, trial_files): _n_scans = nb.load(bold_file).shape[-1] n_scans.append(_n_scans) paradigm = make_paradigm(trial_file) paradigms.append(paradigm) movements = np.loadtxt(mvt_file) tr = 2. drift_model = "Cosine" hrf_model = "Canonical With Derivative" hfcut = 128. frametimes = np.linspace(0, (_n_scans - 1) * tr, _n_scans) design_matrix = make_dmtx( frametimes, paradigm, hrf_model=hrf_model, drift_model=drift_model, hfcut=hfcut, add_regs=movements, add_reg_names=[ "Tx", "Ty", "Tz", "R1", "R2", "R3"]) design_matrices.append(design_matrix) all_frametimes.append(frametimes) # specify contrasts contrasts = {} n_columns = len(design_matrix.names) for i in xrange(paradigm.n_conditions): contrasts['%s' % design_matrix.names[2 * i]] = np.eye( n_columns)[2 * i] # more interesting contrasts""" contrasts['Famous-Unfamiliar'] = contrasts[ 'Famous'] - contrasts['Unfamiliar'] contrasts['Unfamiliar-Famous'] = -contrasts['Famous-Unfamiliar'] contrasts['Famous-Scrambled'] = contrasts[ 'Famous'] - contrasts['Scrambled'] contrasts['Scrambled-Famous'] = -contrasts['Famous-Scrambled'] contrasts['Unfamiliar-Scrambled'] = contrasts[ 'Unfamiliar'] - contrasts['Scrambled'] contrasts['Scrambled-Unfamiliar'] = -contrasts['Unfamiliar-Scrambled'] list_of_contrast_dicts.append(contrasts) # importat maps z_maps = {} effects_maps = {} fmri_glm = FMRILinearModel(task_bold_files, [dm.matrix for dm in design_matrices], mask="compute") fmri_glm.fit(do_scaling=True, model="ar1") # replicate contrasts across runs contrasts = dict((cid, [contrasts[cid] for contrasts in list_of_contrast_dicts]) for cid, cval in contrasts.iteritems()) # compute effects for contrast_id, contrast_val in contrasts.iteritems(): print "\tcontrast id: %s" % contrast_id z_map, eff_map, var_map = fmri_glm.contrast( contrast_val, con_id=contrast_id, output_z=True, output_stat=False, output_effects=True, output_variance=True ) for map_type, out_map in zip(['z', 'effects', 'variance'], [z_map, eff_map, var_map]): map_dir = output_dir / ('%s_maps' % map_type) if not map_dir.exists(): map_dir.makedirs() map_path = map_dir / ('%s.nii.gz' % contrast_id) print "\t\tWriting %s ..." % map_path nb.save(out_map, map_path) # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path if map_type == "variance": effects_maps[contrast_id] = map_path stats_report_dir = output_dir / "report" if not stats_report_dir.exists(): stats_report_dir.makedirs() stats_report_filename = stats_report_dir / "report_stats.html" # remove repeated contrasts contrasts = dict((cid, cval[0]) for cid, cval in contrasts.iteritems()) slicer = 'z' cut_coords = [-20, -10, 0, 10, 20, 30, 40, 50] threshold = 3. cluster_th = 15 generate_subject_stats_report( stats_report_filename, contrasts, z_maps, fmri_glm.mask, anat_affine=anat.get_affine(), anat=anat.get_data(), threshold=threshold, cluster_th=cluster_th, slicer=slicer, cut_coords=cut_coords, design_matrices=design_matrices, subject_id="sub%03d" % subject_id, start_time=stats_start_time, title="GLM for subject %s" % ("sub%03d" % subject_id), # additional ``kwargs`` for more informative report TR=tr, n_scans=n_scans, hfcut=hfcut, drift_model=drift_model, hrf_model=hrf_model, paradigm=dict(("Run_%02i" % (run_id), paradigms[run_id - 1]) for run_id in run_ids), frametimes=dict(("Run_%02i" % (run_id), all_frametimes[run_id - 1]) for run_id in run_ids), # fwhm=fwhm ) return fmri_glm
"fwhm": fwhm } n_jobs = int(os.environ.get('N_JOBS', 1)) if n_jobs > 1: subjects = Parallel(n_jobs=n_jobs, verbose=100)( delayed(run_suject_level1_glm)(subject_data, **kwargs) for subject_data in subjects) else: subjects = [ run_suject_level1_glm(subject_data, **kwargs) for subject_data in subjects ] subjects = [subject for subject in subjects if subject] # level 2 stats_start_time = pretty_time() mask_images = [subject_data.mask for subject_data in subjects] group_mask = nibabel.Nifti1Image( intersect_masks(mask_images).astype(np.int8), nibabel.load(mask_images[0]).get_affine()) nibabel.save(group_mask, os.path.join(task_output_dir, "mask.nii.gz")) print "... done.\r\n" print "Group GLM" contrasts = subjects[0].contrasts subjects_effects_maps = [ subject_data.effects_maps for subject_data in subjects ] group_one_sample_t_test( mask_images,
def _preprocess_and_analysis_subject(subject_data, do_normalize=False, fwhm=0., slicer='z', cut_coords=6, threshold=3., cluster_th=15 ): """ Preprocesses the subject and then fits (mass-univariate) GLM thereupon. """ # sanitize run_ids: # Sub14/BOLD/Run_02/fMR09029-0004-00010-000010-01.nii is garbage, # for example run_ids = range(9) if subject_data['subject_id'] == "Sub14": run_ids = [0] + range(2, 9) subject_data['func'] = [subject_data['func'][0]] + subject_data[ 'func'][2:] subject_data['session_id'] = [subject_data['session_id'][0] ] + subject_data['session_id'][2:] # sanitize subject output dir if not 'output_dir' in subject_data: subject_data['output_dir'] = os.path.join( output_dir, subject_data['subject_id']) # preprocess the data subject_data = do_subject_preproc(SubjectData(**subject_data), do_realign=True, do_coreg=True, do_report=False, do_cv_tc=False ) assert not subject_data.anat is None # norm if do_normalize: subject_data = nipype_do_subject_preproc( subject_data, do_realign=False, do_coreg=False, do_segment=True, do_normalize=True, func_write_voxel_sizes=[3, 3, 3], anat_write_voxel_sizes=[2, 2, 2], fwhm=fwhm, hardlink_output=False, do_report=False ) # chronometry stats_start_time = pretty_time() # to-be merged lists, one item per run paradigms = [] frametimes_list = [] design_matrices = [] # one list_of_contrast_dicts = [] # one dict per run n_scans = [] for run_id in run_ids: _n_scans = len(subject_data.func[run_id]) n_scans.append(_n_scans) # make paradigm paradigm = make_paradigm(getattr(subject_data, 'timing')[run_id]) # make design matrix tr = 2. drift_model = 'Cosine' hrf_model = 'Canonical With Derivative' hfcut = 128. frametimes = np.linspace(0, (_n_scans - 1) * tr, _n_scans) design_matrix = make_dmtx( frametimes, paradigm, hrf_model=hrf_model, drift_model=drift_model, hfcut=hfcut, add_regs=np.loadtxt(getattr(subject_data, 'realignment_parameters')[run_id]), add_reg_names=[ 'Translation along x axis', 'Translation along yaxis', 'Translation along z axis', 'Rotation along x axis', 'Rotation along y axis', 'Rotation along z axis' ] ) # import matplotlib.pyplot as plt # design_matrix.show() # plt.show() paradigms.append(paradigm) design_matrices.append(design_matrix) frametimes_list.append(frametimes) n_scans.append(_n_scans) # specify contrasts contrasts = {} n_columns = len(design_matrix.names) for i in xrange(paradigm.n_conditions): contrasts['%s' % design_matrix.names[2 * i]] = np.eye( n_columns)[2 * i] # more interesting contrasts""" contrasts['Famous-Unfamiliar'] = contrasts[ 'Famous'] - contrasts['Unfamiliar'] contrasts['Unfamiliar-Famous'] = -contrasts['Famous-Unfamiliar'] contrasts['Famous-Scrambled'] = contrasts[ 'Famous'] - contrasts['Scrambled'] contrasts['Scrambled-Famous'] = -contrasts['Famous-Scrambled'] contrasts['Unfamiliar-Scrambled'] = contrasts[ 'Unfamiliar'] - contrasts['Scrambled'] contrasts['Scrambled-Unfamiliar'] = -contrasts['Unfamiliar-Scrambled'] list_of_contrast_dicts.append(contrasts) # importat maps z_maps = {} effects_maps = {} # fit GLM print('\r\nFitting a GLM (this takes time) ..') fmri_glm = FMRILinearModel([nibabel.concat_images(sess_func) for sess_func in subject_data.func], [design_matrix.matrix for design_matrix in design_matrices], mask='compute') fmri_glm.fit(do_scaling=True, model='ar1') print "... done.\r\n" # save computed mask mask_path = os.path.join(subject_data.output_dir, "mask.nii.gz") print "Saving mask image to %s ..." % mask_path nibabel.save(fmri_glm.mask, mask_path) print "... done.\r\n" # replicate contrasts across runs contrasts = dict((cid, [contrasts[cid] for contrasts in list_of_contrast_dicts]) for cid, cval in contrasts.iteritems()) # compute effects for contrast_id, contrast_val in contrasts.iteritems(): print "\tcontrast id: %s" % contrast_id z_map, eff_map = fmri_glm.contrast( contrast_val, con_id=contrast_id, output_z=True, output_stat=False, output_effects=True, output_variance=False ) # store stat maps to disk for map_type, out_map in zip(['z', 'effects'], [z_map, eff_map]): map_dir = os.path.join( subject_data.output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join( map_dir, '%s.nii.gz' % contrast_id) print "\t\tWriting %s ..." % map_path nibabel.save(out_map, map_path) # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path # remove repeated contrasts contrasts = dict((cid, cval[0]) for cid, cval in contrasts.iteritems()) # do stats report stats_report_filename = os.path.join(getattr(subject_data, 'reports_output_dir', subject_data.output_dir), "report_stats.html") generate_subject_stats_report( stats_report_filename, contrasts, z_maps, fmri_glm.mask, threshold=threshold, cluster_th=cluster_th, slicer=slicer, cut_coords=cut_coords, anat=nibabel.load(subject_data.anat).get_data(), anat_affine=nibabel.load(subject_data.anat).get_affine(), design_matrices=design_matrices, subject_id=subject_data.subject_id, start_time=stats_start_time, title="GLM for subject %s" % subject_data.subject_id, # additional ``kwargs`` for more informative report TR=tr, n_scans=n_scans, hfcut=hfcut, drift_model=drift_model, hrf_model=hrf_model, paradigm=dict(("Run_%02i" % (run_id + 1), paradigms[run_id].__dict__) for run_id in run_ids), frametimes=dict(("Run_%02i" % (run_id + 1), frametimes_list[run_id]) for run_id in run_ids), # fwhm=fwhm ) ProgressReport().finish_dir(subject_data.output_dir) print "\r\nStatistic report written to %s\r\n" % stats_report_filename return contrasts, effects_maps, z_maps, mask_path
# to form input for group-level analysis n_jobs = int(os.environ.get('N_JOBS', -1)) group_glm_inputs = Parallel(n_jobs=n_jobs, verbose=100)(delayed( _preprocess_and_analysis_subject)( get_subject_data_from_disk("Sub%02i" % (subject_id + 1)), do_normalize=True, fwhm=[8., 8., 8.], threshold=threshold, slicer=slicer, cut_coords=cut_coords, cluster_th=cluster_th ) for subject_id in range( 16)) # chronometry stats_start_time = pretty_time() # compute group mask print "\r\nComputing group mask ..." mask_images = [subject_glm_results[3] for subject_glm_results in group_glm_inputs] group_mask = nibabel.Nifti1Image(intersect_masks(mask_images ).astype(np.uint8), nibabel.load(mask_images[0] ).get_affine()) print "... done.\r\n" print "Group GLM" contrasts = [ subject_glm_results for subject_glm_results in group_glm_inputs] contrasts = group_glm_inputs[0][0]
def run_suject_level1_glm(subject_data, readout_time=.01392, # seconds tr=.72, dc=True, hrf_model="Canonical with Derivative", drift_model="Cosine", hfcut=100, regress_motion=True, slicer='ortho', cut_coords=None, threshold=3., cluster_th=15, normalize=True, fwhm=0., protocol="MOTOR", func_write_voxel_sizes=None, anat_write_voxel_sizes=None, **other_preproc_kwargs ): """ Function to do preproc + analysis for a single HCP subject (task fMRI) """ add_regs_files = None n_motion_regressions = 6 subject_data.n_sessions = 2 subject_data.tmp_output_dir = os.path.join(subject_data.output_dir, "tmp") if not os.path.exists(subject_data.tmp_output_dir): os.makedirs(subject_data.tmp_output_dir) if not os.path.exists(subject_data.output_dir): os.makedirs(subject_data.output_dir) mem = Memory(os.path.join(subject_data.output_dir, "cache_dir"), verbose=100) # glob design files (.fsf) subject_data.design_files = [os.path.join( subject_data.data_dir, ("MNINonLinear/Results/tfMRI_%s_%s/" "tfMRI_%s_%s_hp200_s4_level1.fsf") % ( protocol, direction, protocol, direction)) for direction in ['LR', 'RL']] assert len(subject_data.design_files) == 2 for df in subject_data.design_files: if not os.path.isfile(df): return if 0x0: subject_data = _do_fmri_distortion_correction( subject_data, dc=dc, fwhm=fwhm, readout_time=readout_time, **other_preproc_kwargs) # chronometry stats_start_time = pretty_time() # merged lists paradigms = [] frametimes_list = [] design_matrices = [] # fmri_files = [] n_scans = [] # for direction, direction_index in zip(['LR', 'RL'], xrange(2)): for sess in xrange(subject_data.n_sessions): direction = ['LR', 'RL'][sess] # glob the design file # design_file = os.path.join(# _subject_data_dir, "tfMRI_%s_%s" % ( # protocol, direction), design_file = subject_data.design_files[sess] # "tfMRI_%s_%s_hp200_s4_level1.fsf" % ( # protocol, direction)) if not os.path.isfile(design_file): print "Can't find design file %s; skipping subject %s" % ( design_file, subject_data.subject_id) return # read the experimental setup print "Reading experimental setup from %s ..." % design_file fsl_condition_ids, timing_files, fsl_contrast_ids, contrast_values = \ read_fsl_design_file(design_file) print "... done.\r\n" # fix timing filenames timing_files = [tf.replace("EVs", "tfMRI_%s_%s/EVs" % ( protocol, direction)) for tf in timing_files] # make design matrix print "Constructing design matrix for direction %s ..." % direction _n_scans = nibabel.load(subject_data.func[sess]).shape[-1] n_scans.append(_n_scans) add_regs_file = add_regs_files[ sess] if not add_regs_files is None else None design_matrix, paradigm, frametimes = make_dmtx_from_timing_files( timing_files, fsl_condition_ids, n_scans=_n_scans, tr=tr, hrf_model=hrf_model, drift_model=drift_model, hfcut=hfcut, add_regs_file=add_regs_file, add_reg_names=[ 'Translation along x axis', 'Translation along yaxis', 'Translation along z axis', 'Rotation along x axis', 'Rotation along y axis', 'Rotation along z axis', 'Differential Translation along x axis', 'Differential Translation along yaxis', 'Differential Translation along z axis', 'Differential Rotation along x axis', 'Differential Rotation along y axis', 'Differential Rotation along z axis' ][:n_motion_regressions] if not add_regs_files is None else None, ) print "... done." paradigms.append(paradigm) frametimes_list.append(frametimes) design_matrices.append(design_matrix) # convert contrasts to dict contrasts = dict((contrast_id, # append zeros to end of contrast to match design np.hstack((contrast_value, np.zeros(len( design_matrix.names) - len(contrast_value))))) for contrast_id, contrast_value in zip( fsl_contrast_ids, contrast_values)) # more interesting contrasts if protocol == 'MOTOR': contrasts['RH-LH'] = contrasts['RH'] - contrasts['LH'] contrasts['LH-RH'] = -contrasts['RH-LH'] contrasts['RF-LF'] = contrasts['RF'] - contrasts['LF'] contrasts['LF-RF'] = -contrasts['RF-LF'] contrasts['H'] = contrasts['RH'] + contrasts['LH'] contrasts['F'] = contrasts['RF'] + contrasts['LF'] contrasts['H-F'] = contrasts['RH'] + contrasts['LH'] - ( contrasts['RF'] - contrasts['LF']) contrasts['F-H'] = -contrasts['H-F'] contrasts = dict((k, v) for k, v in contrasts.iteritems() if "-" in k) # replicate contrasts across sessions contrasts = dict((cid, [cval] * 2) for cid, cval in contrasts.iteritems()) cache_dir = cache_dir = os.path.join(subject_data.output_dir, 'cache_dir') if not os.path.exists(cache_dir): os.makedirs(cache_dir) nipype_mem = NipypeMemory(base_dir=cache_dir) if 0x0: if np.sum(fwhm) > 0.: subject_data.func = nipype_mem.cache(spm.Smooth)( in_files=subject_data.func, fwhm=fwhm, ignore_exception=False, ).outputs.smoothed_files # fit GLM def tortoise(*args): print args print ( 'Fitting a "Fixed Effect" GLM for merging LR and RL ' 'phase-encoding directions for subject %s ...' % ( subject_data.subject_id)) fmri_glm = FMRILinearModel(subject_data.func, [design_matrix.matrix for design_matrix in design_matrices], mask='compute' ) fmri_glm.fit(do_scaling=True, model='ar1') print "... done.\r\n" # save computed mask mask_path = os.path.join(subject_data.output_dir, "mask.nii") print "Saving mask image to %s ..." % mask_path nibabel.save(fmri_glm.mask, mask_path) print "... done.\r\n" z_maps = {} effects_maps = {} map_dirs = {} try: for contrast_id, contrast_val in contrasts.iteritems(): print "\tcontrast id: %s" % contrast_id z_map, eff_map = fmri_glm.contrast( contrast_val, con_id=contrast_id, output_z=True, output_effects=True ) # store stat maps to disk for map_type, out_map in zip(['z', 'effects'], [z_map, eff_map]): map_dir = os.path.join( subject_data.output_dir, '%s_maps' % map_type) map_dirs[map_type] = map_dir if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join( map_dir, '%s_%s.nii' % (map_type, contrast_id)) print "\t\tWriting %s ..." % map_path nibabel.save(out_map, map_path) # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path return effects_maps, z_maps, mask_path, map_dirs except: return None # compute native-space maps and mask stuff = mem.cache(tortoise)( subject_data.func, subject_data.anat) if stuff is None: return None effects_maps, z_maps, mask_path, map_dirs = stuff # remove repeated contrasts contrasts = dict((cid, cval[0]) for cid, cval in contrasts.iteritems()) import json json.dump(dict((k, list(v)) for k, v in contrasts.iteritems()), open(os.path.join(subject_data.tmp_output_dir, "contrasts.json"), "w")) subject_data.contrasts = contrasts if normalize: assert hasattr(subject_data, "parameter_file") subject_data.native_effects_maps = effects_maps subject_data.native_z_maps = z_maps subject_data.native_mask_path = mask_path # warp effects maps and mask from native to standard space (MNI) apply_to_files = [ v for _, v in subject_data.native_effects_maps.iteritems() ] + [subject_data.native_mask_path] tmp = nipype_mem.cache(spm.Normalize)( parameter_file=getattr(subject_data, "parameter_file"), apply_to_files=apply_to_files, write_bounding_box=[[-78, -112, -50], [78, 76, 85]], write_voxel_sizes=func_write_voxel_sizes, write_wrap=[0, 0, 0], write_interp=1, jobtype='write', ignore_exception=False, ).outputs.normalized_files subject_data.mask = hard_link(tmp[-1], subject_data.output_dir) subject_data.effects_maps = dict(zip(effects_maps.keys(), hard_link( tmp[:-1], map_dirs["effects"]))) # warp anat image subject_data.anat = hard_link(nipype_mem.cache(spm.Normalize)( parameter_file=getattr(subject_data, "parameter_file"), apply_to_files=subject_data.anat, write_bounding_box=[[-78, -112, -50], [78, 76, 85]], write_voxel_sizes=anat_write_voxel_sizes, write_wrap=[0, 0, 0], write_interp=1, jobtype='write', ignore_exception=False, ).outputs.normalized_files, subject_data.anat_output_dir) else: subject_data.mask = mask_path subject_data.effects_maps = effects_maps subject_data.z_maps = z_maps return subject_data
def _preprocess_and_analysis_subject(subject_data, slicer='z', cut_coords=6, threshold=3., cluster_th=15, **preproc_params): """ Preprocesses the subject and then fits (mass-univariate) GLM thereup. """ # sanitize run_ids: # Sub14/BOLD/Run_02/fMR09029-0004-00010-000010-01.nii is garbage, # for example run_ids = range(9) if subject_data['subject_id'] == "Sub14": run_ids = [0] + range(2, 9) subject_data['func'] = [subject_data['func'][0] ] + subject_data['func'][2:] subject_data['session_id'] = [subject_data['session_id'][0] ] + subject_data['session_id'][2:] # sanitize subject output dir if not 'output_dir' in subject_data: subject_data['output_dir'] = os.path.join(output_dir, subject_data['subject_id']) # preprocess the data subject_data = do_subject_preproc(subject_data, **preproc_params) # chronometry stats_start_time = pretty_time() # to-be merged lists, one item per run paradigms = [] frametimes_list = [] design_matrices = [] # one list_of_contrast_dicts = [] # one dict per run n_scans = [] for run_id in run_ids: _n_scans = len(subject_data.func[run_id]) n_scans.append(_n_scans) # make paradigm paradigm = make_paradigm(getattr(subject_data, 'timing')[run_id]) # make design matrix tr = 2. drift_model = 'Cosine' hrf_model = 'Canonical With Derivative' hfcut = 128. frametimes = np.linspace(0, (_n_scans - 1) * tr, _n_scans) design_matrix = make_dmtx( frametimes, paradigm, hrf_model=hrf_model, drift_model=drift_model, hfcut=hfcut, add_regs=np.loadtxt( getattr(subject_data, 'realignment_parameters')[run_id]), add_reg_names=[ 'Translation along x axis', 'Translation along yaxis', 'Translation along z axis', 'Rotation along x axis', 'Rotation along y axis', 'Rotation along z axis' ]) # import matplotlib.pyplot as plt # design_matrix.show() # plt.show() paradigms.append(paradigm) design_matrices.append(design_matrix) frametimes_list.append(frametimes) n_scans.append(_n_scans) # specify contrasts contrasts = {} n_columns = len(design_matrix.names) for i in xrange(paradigm.n_conditions): contrasts['%s' % design_matrix.names[2 * i]] = np.eye(n_columns)[2 * i] # more interesting contrasts""" contrasts['Famous-Unfamiliar'] = contrasts['Famous'] - contrasts[ 'Unfamiliar'] contrasts['Unfamiliar-Famous'] = -contrasts['Famous-Unfamiliar'] contrasts[ 'Famous-Scrambled'] = contrasts['Famous'] - contrasts['Scrambled'] contrasts['Scrambled-Famous'] = -contrasts['Famous-Scrambled'] contrasts['Unfamiliar-Scrambled'] = contrasts[ 'Unfamiliar'] - contrasts['Scrambled'] contrasts['Scrambled-Unfamiliar'] = -contrasts['Unfamiliar-Scrambled'] list_of_contrast_dicts.append(contrasts) # importat maps z_maps = {} effects_maps = {} # fit GLM print('\r\nFitting a GLM (this takes time) ..') fmri_glm = FMRILinearModel( [nibabel.concat_images(sess_func) for sess_func in subject_data.func], [design_matrix.matrix for design_matrix in design_matrices], mask='compute') fmri_glm.fit(do_scaling=True, model='ar1') print "... done.\r\n" # save computed mask mask_path = os.path.join(subject_data.output_dir, "mask.nii.gz") print "Saving mask image to %s ..." % mask_path nibabel.save(fmri_glm.mask, mask_path) print "... done.\r\n" # replicate contrasts across runs contrasts = dict( (cid, [contrasts[cid] for contrasts in list_of_contrast_dicts]) for cid, cval in contrasts.iteritems()) # compute effects for contrast_id, contrast_val in contrasts.iteritems(): print "\tcontrast id: %s" % contrast_id z_map, eff_map = fmri_glm.contrast(contrast_val, con_id=contrast_id, output_z=True, output_stat=False, output_effects=True, output_variance=False) # store stat maps to disk for map_type, out_map in zip(['z', 'effects'], [z_map, eff_map]): map_dir = os.path.join(subject_data.output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join(map_dir, '%s.nii.gz' % contrast_id) print "\t\tWriting %s ..." % map_path nibabel.save(out_map, map_path) # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path # remove repeated contrasts contrasts = dict((cid, cval[0]) for cid, cval in contrasts.iteritems()) # do stats report stats_report_filename = os.path.join( getattr(subject_data, 'reports_output_dir', subject_data.output_dir), "report_stats.html") generate_subject_stats_report( stats_report_filename, contrasts, z_maps, fmri_glm.mask, threshold=threshold, cluster_th=cluster_th, slicer=slicer, cut_coords=cut_coords, design_matrices=design_matrices, subject_id=subject_data.subject_id, start_time=stats_start_time, title="GLM for subject %s" % subject_data.subject_id, # additional ``kwargs`` for more informative report TR=tr, n_scans=n_scans, hfcut=hfcut, drift_model=drift_model, hrf_model=hrf_model, paradigm=dict(("Run_%02i" % (run_id + 1), paradigms[run_id]) for run_id in run_ids), frametimes=dict(("Run_%02i" % (run_id + 1), frametimes_list[run_id]) for run_id in run_ids), # fwhm=fwhm ) ProgressReport().finish_dir(subject_data.output_dir) print "\r\nStatistic report written to %s\r\n" % stats_report_filename return contrasts, effects_maps, z_maps, mask_path
def run_suject_level1_glm(subject_data_dir, subject_output_dir, task_id, readout_time=.01392, # seconds tr=.72, do_preproc=False, do_realign=False, do_normalize=False, fwhm=0., report=False, hrf_model="Canonical with Derivative", drift_model="Cosine", hfcut=100, regress_motion=True, slicer='y', cut_coords=6, threshold=3., cluster_th=15 ): """ Function to do preproc + analysis for a single HCP subject (task fMRI) """ # sanitize subject data_dir subject_id = int(os.path.basename(subject_data_dir)) subject_data_dir = os.path.abspath(subject_data_dir) _subject_data_dir = os.path.join(subject_data_dir, "MNINonLinear/Results/") add_regs_files = None if do_preproc: if not os.path.exists(subject_output_dir): os.makedirs(subject_output_dir) # glob fmri files fmri_files = [os.path.join( subject_data_dir, "unprocessed/3T/tfMRI_%s_%s/%s_3T_tfMRI_%s_%s.nii.gz" % ( task_id, direction, subject_id, task_id, direction)) for direction in ["LR", "RL"]] assert len(fmri_files) == 2 # glob anat file anat_file = os.path.join(subject_data_dir, "T1w/T1w_acpc_dc_restore_brain.nii.gz") # assert os.path.isfile(anat_file) if not os.path.isfile(anat_file): anat_file = None # distortion correction ? dc_output = _do_fmri_distortion_correction( fmri_files, subject_data_dir, subject_output_dir, subject_id, task_id, readout_time=readout_time, report=report ) if dc_output is None: return else: fmri_files, realignment_parameters = dc_output # preprocess the data preproc_subject_data = do_subject_preproc(SubjectData( func=fmri_files, anat=anat_file, output_dir=subject_output_dir), do_realign=True, do_normalize=do_normalize, fwhm=fwhm, report=report ) fmri_files = preproc_subject_data.func n_motion_regressions = 6 if do_realign and regress_motion: add_regs_files = realignment_parameters else: n_motion_regressions = 12 # glob fmri files fmri_files = [] for direction in ['LR', 'RL']: fmri_file = os.path.join( _subject_data_dir, "tfMRI_%s_%s/tfMRI_%s_%s.nii.gz" % ( task_id, direction, task_id, direction)) if not os.path.isfile(fmri_file): print "Can't find task fMRI file %s; skipping subject %s" % ( fmri_file, subject_id) return else: fmri_files.append(fmri_file) # glob movement confounds if regress_motion: add_regs_files = [os.path.join(_subject_data_dir, "tfMRI_%s_%s" % ( task_id, direction), "Movement_Regressors.txt") for direction in ["LR", "RL"]] # smooth images if np.sum(fwhm) > 0: print "Smoothing fMRI data (fwhm = %s)..." % fwhm fmri_files = _do_subject_smooth(SubjectData( func=fmri_files, output_dir=subject_output_dir), fwhm=fwhm, report=False ).func print "... done.\r\n" # sanitize subject_output_dir if not os.path.exists(subject_output_dir): os.makedirs(subject_output_dir) # chronometry stats_start_time = pretty_time() # merged lists paradigms = [] frametimes_list = [] design_matrices = [] # fmri_files = [] n_scans = [] for direction, direction_index in zip(['LR', 'RL'], xrange(2)): # glob the design file design_file = os.path.join(_subject_data_dir, "tfMRI_%s_%s" % ( task_id, direction), "tfMRI_%s_%s_hp200_s4_level1.fsf" % ( task_id, direction)) if not os.path.isfile(design_file): print "Can't find design file %s; skipping subject %s" % ( design_file, subject_id) return # read the experimental setup print "Reading experimental setup from %s ..." % design_file fsl_condition_ids, timing_files, fsl_contrast_ids, contrast_values = \ read_design_fsl_design_file(design_file) print "... done.\r\n" # fix timing filenames timing_files = _insert_directory_in_file_name( timing_files, "tfMRI_%s_%s" % (task_id, direction), 1) # make design matrix print "Constructing design matrix for direction %s ..." % direction _n_scans = nibabel.load(fmri_files[direction_index]).shape[-1] n_scans.append(_n_scans) add_regs_file = add_regs_files[ direction_index] if not add_regs_files is None else None, design_matrix, paradigm, frametimes = make_dmtx_from_timing_files( timing_files, fsl_condition_ids, n_scans=_n_scans, tr=tr, hrf_model=hrf_model, drift_model=drift_model, hfcut=hfcut, add_regs_file=add_regs_file, add_reg_names=[ 'Translation along x axis', 'Translation along yaxis', 'Translation along z axis', 'Rotation along x axis', 'Rotation along y axis', 'Rotation along z axis', 'Differential Translation along x axis', 'Differential Translation along yaxis', 'Differential Translation along z axis', 'Differential Rotation along x axis', 'Differential Rotation along y axis', 'Differential Rotation along z axis' ][:n_motion_regressions] if not add_regs_files is None else None, ) print "... done." paradigms.append(paradigm) frametimes_list.append(frametimes) design_matrices.append(design_matrix) # convert contrasts to dict contrasts = dict((contrast_id, # append zeros to end of contrast to match design np.hstack((contrast_value, np.zeros(len( design_matrix.names) - len(contrast_value))))) for contrast_id, contrast_value in zip( fsl_contrast_ids, contrast_values)) # more interesting contrasts if task_id == 'MOTOR': contrasts['RH-LH'] = contrasts['RH'] - contrasts['LH'] contrasts['LH-RH'] = -contrasts['RH-LH'] contrasts['RF-LF'] = contrasts['RF'] - contrasts['LF'] contrasts['LF-RF'] = -contrasts['RF-LF'] contrasts['H'] = contrasts['RH'] + contrasts['LH'] contrasts['F'] = contrasts['RF'] + contrasts['LF'] contrasts['H-F'] = contrasts['RH'] + contrasts['LH'] - ( contrasts['RF'] - contrasts['LF']) contrasts['F-H'] = -contrasts['H-F'] # importat maps z_maps = {} effects_maps = {} # replicate contrasts across sessions contrasts = dict((cid, [cval] * 2) for cid, cval in contrasts.iteritems()) # compute effects mask_path = os.path.join(subject_output_dir, "mask.nii.gz") skip = os.path.isfile(mask_path) if skip: for contrast_id, contrast_val in contrasts.iteritems(): for map_type in ['z', 'effects']: map_dir = os.path.join( subject_output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join( map_dir, '%s.nii.gz' % contrast_id) if not os.path.exists(map_path): skip = 0 break # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path if skip: print "Skipping subject %s..." % ( subject_id) # fit GLM if not skip: print ( 'Fitting a "Fixed Effect" GLM for merging LR and RL phase-encoding ' 'directions for subject %s ...' % subject_id) fmri_glm = FMRILinearModel(fmri_files, [design_matrix.matrix for design_matrix in design_matrices], mask='compute' ) fmri_glm.fit(do_scaling=True, model='ar1') print "... done.\r\n" # save computed mask mask_path = os.path.join(subject_output_dir, "mask.nii.gz") print "Saving mask image to %s ..." % mask_path nibabel.save(fmri_glm.mask, mask_path) print "... done.\r\n" # compute effects for contrast_id, contrast_val in contrasts.iteritems(): print "\tcontrast id: %s" % contrast_id z_map, eff_map = fmri_glm.contrast( contrast_val, con_id=contrast_id, output_z=True, output_effects=True ) # store stat maps to disk for map_type, out_map in zip(['z', 'effects'], [z_map, eff_map]): map_dir = os.path.join( subject_output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join( map_dir, '%s.nii.gz' % contrast_id) print "\t\tWriting %s ..." % map_path nibabel.save(out_map, map_path) # collect zmaps for contrasts we're interested in if map_type == 'z': z_maps[contrast_id] = map_path if map_type == 'effects': effects_maps[contrast_id] = map_path # remove repeated contrasts contrasts = dict((cid, cval[0]) for cid, cval in contrasts.iteritems()) # do stats report if 0x0: anat_img = load_specific_vol(fmri_files[0], 0)[0] stats_report_filename = os.path.join(subject_output_dir, "reports", "report_stats.html") generate_subject_stats_report( stats_report_filename, contrasts, z_maps, nibabel.load(mask_path), anat=anat_img.get_data(), anat_affine=anat_img.get_affine(), threshold=threshold, cluster_th=cluster_th, slicer=slicer, cut_coords=cut_coords, design_matrices=design_matrices, subject_id=subject_id, start_time=stats_start_time, title="GLM for subject %s" % subject_id, # additional ``kwargs`` for more informative report TR=tr, n_scans=n_scans, hfcut=hfcut, drift_model=drift_model, hrf_model=hrf_model, paradigm={'LR': paradigms[0].__dict__, 'RL': paradigms[1].__dict__}, frametimes={'LR': frametimes_list[0], 'RL': frametimes_list[1]}, fwhm=fwhm ) ProgressReport().finish_dir(subject_output_dir) print "\r\nStatistic report written to %s\r\n" % stats_report_filename return contrasts, effects_maps, z_maps, mask_path