def func_ttest(subj_list, out_dir, deriv_dir, sess, strA, strB, phase): # set up ETAC script list_A = [] list_B = [] for subj in subj_list: list_A.append(subj) list_A.append( os.path.join(deriv_dir, subj, sess, f"{phase}_tentAvg_{strA}+tlrc")) list_B.append(subj) list_B.append( os.path.join(deriv_dir, subj, sess, f"{phase}_tentAvg_{strB}+tlrc")) h_cmd = f""" module load afni-20.2.06 cd {out_dir} 3dttest++ \\ -paired \\ -mask Group_GM_intersect_mask+tlrc \\ -prefix {phase}_{strA}-{strB}_tt \\ -setA A {" ".join(list_A)} \\ -setB B {" ".join(list_B)} """ func_sbatch(h_cmd, 2, 4, 4, "vCATtt", out_dir)
def func_etac(subj_list, out_dir, deriv_dir, sess, strA, strB, phase): # set up ETAC script list_A = [] list_B = [] for subj in subj_list: list_A.append(subj) list_A.append( os.path.join(deriv_dir, subj, sess, f"{phase}_tentAvg_{strA}+tlrc")) list_B.append(subj) list_B.append( os.path.join(deriv_dir, subj, sess, f"{phase}_tentAvg_{strB}+tlrc")) h_cmd = f""" module load afni-20.2.06 cd {out_dir} # -ETAC_blur 4 6 8 3dttest++ \\ -paired \\ -mask Group_GM_intersect_mask+tlrc \\ -prefix {phase}_{strA}-{strB} \\ -prefix_clustsim {phase}_{strA}-{strB}_clustsim \\ -ETAC \\ -ETAC_opt NN=2:sid=2:hpow=0:pthr=0.01,0.005,0.001:name=NN2 \\ -setA A {" ".join(list_A)} \\ -setB B {" ".join(list_B)} 3dcopy {phase}_{strA}-{strB}_clustsim.NN2.ETACmask.global.2sid.5perc.nii.gz \ FINAL_{phase}_{strA}-{strB}+tlrc """ func_sbatch(h_cmd, 40, 6, 10, "vCATetac", out_dir)
def func_clean_volreg(work_dir, phase_list, subj_num): """ Step 7: Clean volreg data 1) Censor potentially bad volumes to avoid biasing scale step. Note: This rarely has an effect. """ # Determine minimum value, make mask # beware the jabberwocky i.e. expanding braces in 3dMean for phase in phase_list: epi_list = func_epi_list(phase, work_dir) if not os.path.exists( os.path.join(work_dir, f"{phase}_minVal_mask+tlrc.HEAD")): h_cmd = f""" cd {work_dir} 3dMean \ -datum short \ -prefix tmp_mean_{phase} \ tmp_run-{{1..{len(epi_list)}}}_{phase}_min+tlrc 3dcalc \ -a tmp_mean_{phase}+tlrc \ -expr 'step(a-0.999)' \ -prefix {phase}_minVal_mask """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}min", work_dir) # make clean data for run in epi_list: if not os.path.exists( os.path.join(work_dir, f"{run}_volreg_clean+tlrc.HEAD")): h_cmd = f""" cd {work_dir} 3dcalc \ -a {run}_warp+tlrc \ -b {phase}_minVal_mask+tlrc \ -expr 'a*b' \ -prefix {run}_volreg_clean """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}cle", work_dir)
def func_register(atlas, work_dir, subj_num): """ Step 5: Calculate normalization 1) This step will perform the rigid alignments of T1->EPI and non-linear diffeomorphic of T1->Template. """ if not os.path.exists(os.path.join(work_dir, "struct_ns+tlrc.HEAD")): h_cmd = f""" cd {work_dir} align_epi_anat.py \ -anat2epi \ -anat struct+orig \ -save_skullstrip \ -suffix _al_junk \ -epi epi_vrBase+orig \ -epi_base 0 \ -epi_strip 3dAutomask \ -cost lpc+ZZ \ -giant_move \ -check_flip \ -volreg off \ -tshift off auto_warp.py \ -base {atlas} \ -input struct_ns+orig \ -skull_strip_input no 3dbucket \ -DAFNI_NIFTI_VIEW=tlrc \ -prefix struct_ns \ awpy/struct_ns.aw.nii* cp awpy/anat.un.aff.Xat.1D . cp awpy/anat.un.aff.qw_WARP.nii . """ func_sbatch(h_cmd, 1, 4, 4, f"{subj_num}dif", work_dir)
def func_blur(work_dir, subj_num, blur_mult): """ Step 8: Blur EPI data 1) Blur kernel is size = blur_multiplier * voxel dim, rounded up to nearest int. FWHM. """ # Blur epi_list = [ x.split("_vol")[0] for x in os.listdir(work_dir) if fnmatch.fnmatch(x, "*volreg_clean+tlrc.HEAD") ] for run in epi_list: if not os.path.exists(os.path.join(work_dir, f"{run}_blur+tlrc.HEAD")): # calc voxel dim i h_cmd = f""" module load afni-20.2.06 3dinfo -di {work_dir}/{run}+orig """ h_gs = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) h_gs_out = h_gs.communicate()[0] grid_size = h_gs_out.decode("utf-8").strip() blur_size = math.ceil(blur_mult * float(grid_size)) # do blur h_cmd = f""" cd {work_dir} 3dmerge \ -1blur_fwhm {blur_size} \ -doall \ -prefix {run}_blur \ {run}_volreg_clean+tlrc """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}blur", work_dir)
def func_scale(work_dir, phase_list, subj_num): """ Step 10: Scale data 1) Data is scaled by mean signal """ for phase in phase_list: epi_list = func_epi_list(phase, work_dir) for run in epi_list: if not os.path.exists( os.path.join(work_dir, f"{run}_scale+tlrc.HEAD")): h_cmd = f""" cd {work_dir} 3dTstat -prefix tmp_tstat_{run} {run}_blur+tlrc 3dcalc -a {run}_blur+tlrc \ -b tmp_tstat_{run}+tlrc \ -c {phase}_minVal_mask+tlrc \ -expr 'c * min(200, a/b*100)*step(a)*step(b)' \ -prefix {run}_scale """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}scale", work_dir)
def func_tiss_masks(work_dir, subj_num, atropos_dict, atropos_dir): """ Step 9: Make union and tissue masks 1) Make a union mask, where sufficient signal exists for both T1w and T2*w at each voxel for analyses. Incorporated at the group-level analysis. 2) Make tissue masks. The WM mask will be used later to derive nuissance regressors for the REML. Note: this references some custom masks, and is based in atropos rather than in AFNIs tiss seg protocol. """ epi_list = [ x.split("_vol")[0] for x in os.listdir(work_dir) if fnmatch.fnmatch(x, "*volreg_clean+tlrc.HEAD") ] # Make EPI-T1 union mask (mask_epi_anat) if not os.path.exists(os.path.join(work_dir, "mask_epi_anat+tlrc.HEAD")): for run in epi_list: if not os.path.exists( os.path.join(work_dir, f"tmp_mask.{run}_blur+tlrc.HEAD")): h_cmd = f""" module load afni-20.2.06 cd {work_dir} 3dAutomask -prefix tmp_mask.{run} {run}_blur+tlrc """ h_mask = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) h_mask.wait() h_cmd = f""" cd {work_dir} 3dmask_tool \ -inputs tmp_mask.*+tlrc.HEAD \ -union \ -prefix tmp_mask_allRuns 3dresample \ -master tmp_mask_allRuns+tlrc \ -input struct_ns+tlrc \ -prefix tmp_anat_resamp 3dmask_tool \ -dilate_input 5 -5 \ -fill_holes \ -input tmp_anat_resamp+tlrc \ -prefix tmp_mask_struct 3dmask_tool \ -input tmp_mask_allRuns+tlrc tmp_mask_struct+tlrc \ -inter \ -prefix mask_epi_anat 3dABoverlap \ -no_automask tmp_mask_allRuns+tlrc tmp_mask_struct+tlrc | \ tee out.mask_ae_overlap.txt """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}uni", work_dir) # Make tissue-class masks # I like Atropos better than AFNI's way, so use those priors h_ref = f"{epi_list[0]}_blur+tlrc" for key in atropos_dict: h_tiss = atropos_dict[key] if not os.path.exists( os.path.join(work_dir, f"final_mask_{h_tiss}_eroded+tlrc.HEAD")): h_cmd = f""" module load c3d-1.0.0-gcc-8.2.0 cd {work_dir} c3d \ {atropos_dir}/Prior{key}.nii.gz \ -thresh 0.3 1 1 0 \ -o tmp_{h_tiss}_bin.nii.gz 3dresample \ -master {h_ref} \ -rmode NN \ -input tmp_{h_tiss}_bin.nii.gz \ -prefix final_mask_{h_tiss}+tlrc 3dmask_tool \ -input tmp_{h_tiss}_bin.nii.gz \ -dilate_input -1 \ -prefix tmp_mask_{h_tiss}_eroded 3dresample \ -master {h_ref} \ -rmode NN \ -input tmp_mask_{h_tiss}_eroded+orig \ -prefix final_mask_{h_tiss}_eroded """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}atr", work_dir)
def func_volreg_warp(work_dir, phase_list, subj_num, blip_tog): """ Step 6: Warp EPI data to template space 1) This step will perform the rigid alignments of T1-EPI (A) EPI-EPI base volume (B), and non-linear diffeomorphic of T1-Template (C). Note blip distortion map (D). 2) Together, then, we will have T1-EPI (A), EPI-EPI base volume (B), and non-linear diffeomorphic of T1-Template (C) and possibly blip distortion map (D) matrices. 3) It will then concatenate these warp matrices, and warp EPI data from raw/native space to template space via W=A'+B+C+D. Thus, only one interpolation of the epi data occurs. """ scan_dict = {} h_str = "_blip+orig" if blip_tog == 1 else "+orig" for phase in phase_list: h_list = [ x.split(".")[0] for x in os.listdir(work_dir) if fnmatch.fnmatch(x, f"run-*{phase}{h_str}.HEAD") ] h_list.sort() scan_dict[phase] = h_list scan_list = flatten_list(list(scan_dict.values())) for h_run in scan_list: # get run str run = h_run.split("_blip")[0] if blip_tog == 1 else h_run.split("+")[0] # Calculate volreg for e/run if not os.path.exists(os.path.join(work_dir, f"mat.{run}.vr.aff12.1D")): h_cmd = f""" cd {work_dir} 3dvolreg \ -verbose \ -zpad 1 \ -base epi_vrBase+orig \ -1Dfile dfile.{run}.1D \ -prefix {run}_volreg \ -cubic \ -1Dmatrix_save mat.{run}.vr.aff12.1D \ {h_run} """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}vre", work_dir) # set up, warp EPI to template if not os.path.exists(os.path.join(work_dir, f"{run}_warp+tlrc.HEAD")): # get grid size h_cmd = f""" module load afni-20.2.06 3dinfo -di {work_dir}/{run}+orig """ h_gs = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) h_gs_out = h_gs.communicate()[0] grid_size = h_gs_out.decode("utf-8").strip() # concatenate matrices h_cmd = f""" module load afni-20.2.06 cd {work_dir} cat_matvec \ -ONELINE \ anat.un.aff.Xat.1D \ struct_al_junk_mat.aff12.1D -I \ mat.{run}.vr.aff12.1D > mat.{run}.warp.aff12.1D """ h_cat = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) h_cat.wait() # warp epi, mask into template space nwarp_list = [ "anat.un.aff.qw_WARP.nii", f"mat.{run}.warp.aff12.1D" ] if blip_tog == 1: nwarp_list.append("blip_warp_For_WARP+orig") h_cmd = f""" cd {work_dir} 3dNwarpApply \ -master struct_ns+tlrc \ -dxyz {grid_size} \ -source {run}+orig \ -nwarp '{" ".join(nwarp_list)}' \ -prefix {run}_warp """ func_sbatch(h_cmd, 2, 4, 4, f"{subj_num}war", work_dir) # Update - don't waste computation time warping # simple mask into template space. Just make # mask from warped EPI data if not os.path.exists( os.path.join(work_dir, f"tmp_{run}_min+tlrc.HEAD")): h_cmd = f""" module load afni-20.2.06 cd {work_dir} 3dcalc \ -overwrite \ -a {run}_warp+tlrc \ -expr 1 \ -prefix tmp_{run}_mask 3dTstat \ -min \ -prefix tmp_{run}_min \ tmp_{run}_mask+tlrc """ h_mask = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) h_mask.wait()
def func_fmap_corr(work_dir, subj_num, phase_list): """ Step 3: Blip correct data 1) Calculate median of AP, PA files 2) Compute midpoint between media files 3) Apply warp to de-distort (unwarp) EPI data Note: If acq = LR, fmap = RL: base = LR, source = RL -pmNAMES RL LR unwarp LR with LR_WARP """ # create median datasets and masks for h_dir in ["AP", "PA"]: if not os.path.exists( os.path.join(work_dir, f"tmp_med_masked_{h_dir}+orig.HEAD")): h_cmd = f""" cd {work_dir} 3dTstat \ -median \ -prefix tmp_med_{h_dir} \ blip_{h_dir}+orig 3dAutomask \ -apply_prefix tmp_med_masked_{h_dir} \ tmp_med_{h_dir}+orig """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}med", work_dir) # compute midpoint between fmaps if not os.path.exists( os.path.join(work_dir, "blip_warp_For_WARP+orig.HEAD")): h_cmd = f""" cd {work_dir} 3dQwarp \ -plusminus \ -pmNAMES Rev For \ -pblur 0.05 0.05 \ -blur -1 -1 \ -noweight \ -minpatch 9 \ -source tmp_med_masked_PA+orig \ -base tmp_med_masked_AP+orig \ -prefix blip_warp """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}qwa", work_dir) # unwarp run data (de-distort), apply header for phase in phase_list: epi_list = func_epi_list(phase, work_dir) for run in epi_list: if not os.path.exists( os.path.join(work_dir, f"{run}_blip+orig.HEAD")): h_cmd = f""" cd {work_dir} 3dNwarpApply \ -quintic \ -nwarp blip_warp_For_WARP+orig \ -source {run}+orig \ -prefix {run}_blip 3drefit \ -atrcopy blip_AP+orig \ IJK_TO_DICOM_REAL \ {run}_blip+orig """ func_sbatch(h_cmd, 1, 2, 4, f"{subj_num}nwar", work_dir)
def func_job(work_dir, subj, ses, phase, decon_type, seed_dict, stim_dur): # # for testing # work_dir = "/scratch/madlab/nate_ppi/derivatives" # subj = "sub-1040" # ses = "ses-S1" # phase = "Study" # decon_type = "2GAM" # seed_dict = {"LHC": "-24 -12 -22"} # stim_dur = 2 """ Step 1: Clean Data Create "clean data" by removing effects of no interest (baseline regressors) from scaled data. """ subj_dir = os.path.join(work_dir, subj, ses) subj_num = subj.split("-")[1] # get TR h_cmd = ( f"module load afni-20.2.06 \n 3dinfo -tr {subj_dir}/run-1_{phase}_scale+tlrc" ) h_tr = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) len_tr = float(h_tr.communicate()[0].decode("utf-8").strip()) # get proper brick length # REML appends an extra brick because # "reasons". Account for AFNIs random # 0-1 indexing h_cmd = f"module load afni-20.2.06 \n 3dinfo -nv {subj_dir}/{phase}_decon_cbucket_REML+tlrc" h_len = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) len_wrong = h_len.communicate()[0].decode("utf-8").strip() len_right = int(len_wrong) - 2 # list all scale files scale_list = [ x.split(".")[0] for x in os.listdir(subj_dir) if fnmatch.fnmatch(x, f"*{phase}*scale+tlrc.HEAD") ] scale_list.sort() # make clean data if not os.path.exists(os.path.join(subj_dir, f"CleanData_{phase}+tlrc.HEAD")): # list undesirable sub-bricks (those starting with Run or mot) no_int = [] with open(os.path.join(subj_dir, f"X.{phase}_decon.xmat.1D")) as f: h_file = f.readlines() for line in h_file: if line.__contains__("ColumnLabels"): col_list = ( line.replace("#", "").split('"')[1].replace(" ", "").split(";") ) for i, j in enumerate(col_list): if fnmatch.fnmatch(j, "Run*") or fnmatch.fnmatch(j, "mot*"): no_int.append(f"{str(i)}") # strip extra sub-brick, make clean data by removing # effects of no interest from concatenated runs h_cmd = f""" cd {subj_dir} 3dTcat -prefix tmp_{phase}_cbucket -tr {len_tr} "{phase}_decon_cbucket_REML+tlrc[0..{len_right}]" 3dSynthesize -prefix tmp_effNoInt_{phase} -matrix X.{phase}_decon.xmat.1D \ -cbucket tmp_{phase}_cbucket+tlrc -select {" ".join(no_int)} -cenfill nbhr 3dTcat -prefix tmp_all_runs_{phase} -tr {len_tr} {" ".join(scale_list)} 3dcalc -a tmp_all_runs_{phase}+tlrc -b tmp_effNoInt_{phase}+tlrc -expr 'a-b' -prefix CleanData_{phase} """ func_sbatch(h_cmd, 1, 4, 1, f"{subj_num}cle", subj_dir) # %% """ Step 2: Seed Time Series 1. Make HRF model, and seed from coordinates. 2. Extract timeseries from seed ROI. 3. Deconvolve HRF from timeseries (solve RHS). 4. Upsample. """ # find smallest multiplier that returns int for resampling res_multiplier = 2 status = True while status: if ((len_tr * res_multiplier) % 2) == 0: status = False else: res_multiplier += 1 # set status resample_decision = "easy" if res_multiplier <= 32 else "hard" # make ideal HRF, use same model as deconvolution # TENT not supported. if not os.path.exists(os.path.join(subj_dir, "HRF_model.1D")): if decon_type == "dmBLOCK": no_data = f"{14 + stim_dur} 1" hrf_model = "BLOCK(1,1)" elif decon_type == "GAM": no_data = f"{round((1 / len_tr) * 13)} {len_tr}" hrf_model = "GAM" elif decon_type == "2GAM": no_data = f"{round((1 / len_tr) * 19)} {len_tr}" hrf_model = "TWOGAMpw(4,5,0.2,12,7)" h_cmd = f""" cd {subj_dir} 3dDeconvolve -polort -1 \ -nodata {no_data} \ -num_stimts 1 \ -stim_times 1 1D:0 '{hrf_model}' \ -x1D HRF_model.1D -x1D_stop """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}hrf", subj_dir) # get seed TS, solve RHS for key in seed_dict: # make seed, get TS if not os.path.exists(os.path.join(subj_dir, f"Seed_{key}_neural_us.1D")): h_cmd = f""" cd {subj_dir} echo {seed_dict[key]} | 3dUndump -xyz \ -srad 3 -master CleanData_{phase}+tlrc \ -prefix Seed_{key} - 3dmaskave -quiet -mask Seed_{key}+tlrc CleanData_{phase}+tlrc > Seed_{key}_orig.1D """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}mksd", subj_dir) # solve RHS, then upsample # I want to use -l2lasso, but I'm scared if not os.path.exists(os.path.join(subj_dir, f"Seed_{key}_neural_us.1D")): h_cmd = f""" cd {subj_dir} 3dTfitter -RHS Seed_{key}_orig.1D -FALTUNG HRF_model.1D tmp.1D 012 0 1dtranspose tmp.1D > Seed_{key}_neural.1D """ func_sbatch(h_cmd, 8, 1, 4, f"{subj_num}flt", subj_dir) if resample_decision == "easy": h_cmd = f""" module load afni-20.2.06 1dUpsample {res_multiplier} {subj_dir}/Seed_{key}_neural.1D \ > {subj_dir}/Seed_{key}_neural_us.1D """ h_sp = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) elif resample_decision == "hard": seed_file = open(f"{subj_dir}/Seed_{key}_neural.1D", "r") h_ts = seed_file.readlines() seed_ts = [float(x.strip()) for x in h_ts] seed_us = func_upsample(seed_ts, len_tr, 1) with open(f"{subj_dir}/Seed_{key}_neural_us.1D", "w") as seed_out: for value in seed_us: seed_out.write("%s\n" % value) # %% """ Step 3: Make Behavior Time Series 1. Make behavior binary vectors from timing files. 2. Upsample w/o interpolation. 3. Extract behavior portions of seed neural timeseries (intx). 4. Downsample intx via Bash. 5. Convolve intx with HRF model. """ # list of timing files time_dir = os.path.join(subj_dir, "timing_files") tf_list = [ os.path.join(time_dir, x) for x in os.listdir(time_dir) if fnmatch.fnmatch(x, f"tf_{phase}*.txt") ] # list of run length in seconds run_len = [] num_vol = [] for i in scale_list: h_cmd = f"module load afni-20.2.06 \n 3dinfo -ntimes {subj_dir}/{i}" h_sp = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) h_vol = int(h_sp.communicate()[0].decode("utf-8").strip()) num_vol.append(h_vol) run_len.append(h_vol * len_tr) for tf_path in tf_list: # tf_path = tf_list[0] h_beh = tf_path.split(".")[0].split("_")[-1] # get upsampled behavior binary file if not os.path.exists(os.path.join(subj_dir, f"Beh_{h_beh}_us.1D")): h_cmd = f""" module load afni-20.2.06 cd {subj_dir} timing_tool.py -timing {tf_path} -tr {len_tr} \ -stim_dur {stim_dur} -run_len {" ".join(map(str, run_len))} \ -min_frac 0.3 -timing_to_1D Beh_{h_beh}_bin.1D """ # func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}{h_beh}", subj_dir) h_sp = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) (h_err, h_out) = h_sp.communicate() h_sp.wait() if resample_decision == "easy": h_cmd = f""" module load afni-20.2.06 awk '{{for(j=0;j<{res_multiplier};j++)print}}' \ {subj_dir}/Beh_{h_beh}_bin.1D > {subj_dir}/Beh_{h_beh}_us.1D """ h_sp = subprocess.Popen(h_cmd, shell=True, stdout=subprocess.PIPE) elif resample_decision == "hard": tf_file = open(f"{subj_dir}/Beh_{h_beh}_bin.1D", "r") h_tf = tf_file.readlines() tf_ts = [int(x.strip()) for x in h_tf] # Note: don't interpolate upsample tf_us = func_upsample(tf_ts, len_tr, 0) with open(f"{subj_dir}/Beh_{h_beh}_us.1D", "w") as tf_out: for value in tf_us: tf_out.write("%s\n" % value) # multiply beh bin file by clean neural to get intx term. # downsample in bash, pad final vol for key in seed_dict: if not os.path.exists( os.path.join(subj_dir, f"Seed_{key}_{h_beh}_neural.1D") ): ds_factor = ( res_multiplier if resample_decision == "easy" else int(1000 * len_tr) ) h_cmd = f""" cd {subj_dir} 1deval -a Seed_{key}_neural_us.1D -b Beh_{h_beh}_us.1D \ -expr 'a*b' > Seed_{key}_{h_beh}_neural_us.1D cat Seed_{key}_{h_beh}_neural_us.1D | \ awk -v n={ds_factor} 'NR%n==0' > Seed_{key}_{h_beh}_neural.1D && \ echo 0 >> Seed_{key}_{h_beh}_neural.1D """ func_sbatch(h_cmd, 2, 1, 1, f"{subj_num}nts", subj_dir) # convolve seed beh neural (intx) with HRF if not os.path.exists( os.path.join(subj_dir, f"Final_{key}_{h_beh}_timeSeries.1D") ): h_cmd = f""" cd {subj_dir} waver -FILE {len_tr} HRF_model.1D \ -peak 1 -TR {len_tr} \ -input Seed_{key}_{h_beh}_neural.1D \ -numout {sum(num_vol)} > Final_{key}_{h_beh}_timeSeries.1D """ func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}ds", subj_dir) # %% """ Step 4: Rerun Deconvolution Same decon as before, add Seed and Behavior timeseries. """ # Write decon script if not os.path.exists(os.path.join(subj_dir, f"X.{phase}_decon_ppi.xmat.1D")): # determine motion list mot_list = [ x for x in os.listdir(subj_dir) if fnmatch.fnmatch(x, f"mot_demean_{phase}.*.1D") ] mot_list.sort() # make timing file dict tf_dict = {} for i in tf_list: tmp = i.split("_")[-1] beh = tmp.split(".")[0] tf_dict[beh] = i # make ppi dict ppi_dict = {} for key in seed_dict: ppi_dict[key] = f"Seed_{key}_orig.1D" for beh in tf_dict: ppi_dict[f"{key}_{beh}"] = f"Final_{key}_{beh}_timeSeries.1D" # write decon script, generate matrices and REML_cmd decon_script = os.path.join(subj_dir, f"ppi_decon_{phase}.sh") with open(decon_script, "w") as script: script.write( func_decon_ppi( scale_list, mot_list, tf_dict, f"censor_{phase}_combined.1D", phase, decon_type, ppi_dict, ) ) # run decon script to generate matrices h_cmd = f"cd {subj_dir} \n source {decon_script}" func_sbatch(h_cmd, 1, 1, 1, f"{subj_num}dcn", subj_dir) # run REML if not os.path.exists( os.path.join(subj_dir, f"{phase}_decon_ppi_stats_REML+tlrc.HEAD") ): h_cmd = f"cd {subj_dir} \n tcsh -x {phase}_decon_ppi_stats.REML_cmd -dsort {phase}_WMe_rall+tlrc" func_sbatch(h_cmd, 10, 4, 6, f"{subj_num}rml", subj_dir)