Summary of what happened:
Hi all,
I am trying to run FSL feat in terminal with the .fsf file but it seems to just be running without anything happening. I am trying to run contrasts on a block design task where the images have already been processed using fmriprep. my script and design files are below. Any suggestions?
Command used (and if a helper script was used, a link to the helper script or the command generated):
#!/bin/bash
# Script to create and run stats-only FEAT analyses for subjects 1-10
# Optimized for preprocessed data from fMRIPrep - using prepared motion parameters
# Load FSL
module load fsl/6.0.3-cuda9.1
# Directories
FMRIPREP_DIR="/work/cnelab/dtmt_fmri/mri/bids/derivatives/fmriprep"
OUTPUT_BASE_DIR="/work/cnelab/dtmt_fmri/mri/analysis/fsl_analysis/dtmt_fmri"
CONFOUNDS_BASE_DIR="/work/cnelab/dtmt_fmri/mri/analysis/fsl_analysis/dtmt_fmri"
TIMING_DIR="/work/cnelab/dtmt_fmri/mri/analysis/timing_files"
# Parameters
TR=0.8
Z_THRESH=2.8 # p<0.005 threshold
CLUSTER_P_THRESH=0.05 # Cluster-level correction
# Create master output directory if it doesn't exist
mkdir -p "$OUTPUT_BASE_DIR"
# Function to process a single subject
process_subject() {
local subject_num=$1
local SUBJECT_ID="sub-${subject_num}"
echo "========================================================="
echo "Processing $SUBJECT_ID"
echo "========================================================="
# Create subject-specific directories
local OUTPUT_DIR="${OUTPUT_BASE_DIR}/${SUBJECT_ID}"
mkdir -p "$OUTPUT_DIR"
# Input data paths
local FUNC_DATA="${FMRIPREP_DIR}/${SUBJECT_ID}/func/${SUBJECT_ID}_task-dtmt_space-MNI152NLin2009cAsym_res-2_desc-preproc_bold.nii.gz"
local MASK_FILE="${FMRIPREP_DIR}/${SUBJECT_ID}/func/${SUBJECT_ID}_task-dtmt_space-MNI152NLin2009cAsym_res-2_desc-brain_mask.nii.gz"
local CONFOUNDS_FILE="${CONFOUNDS_BASE_DIR}/${SUBJECT_ID}/confounds/motion_params.txt"
# Check if files exist
if [ ! -f "$FUNC_DATA" ]; then
echo "ERROR: Functional data not found: $FUNC_DATA"
return 1
fi
if [ ! -f "$MASK_FILE" ]; then
echo "ERROR: Mask file not found: $MASK_FILE"
return 1
fi
# Check timing files
for cond in timing_file_motor timing_file_a timing_file_b timing_file_fix; do
if [ ! -f "${TIMING_DIR}/${cond}.txt" ]; then
echo "ERROR: Timing file not found: ${TIMING_DIR}/${cond}.txt"
echo "Make sure you've run the timing extraction script first"
return 1
fi
done
# Check for confounds file
if [ ! -f "$CONFOUNDS_FILE" ]; then
echo "ERROR: Confounds file not found: $CONFOUNDS_FILE"
return 1
fi
# Additional data validation
# Check dimensions and properties of the functional data
local DIMS=$(fslhd "$FUNC_DATA" | grep -E "^dim[1-4]" | awk '{print $2}' | paste -sd "x")
local NVOLS=$(fslnvols "$FUNC_DATA")
echo "Functional data dimensions: $DIMS with $NVOLS volumes"
# Check mask coverage (percentage of non-zero voxels)
local MASK_COVERAGE=$(fslstats "$MASK_FILE" -M)
echo "Mask coverage: $MASK_COVERAGE (should be close to 1.0 for binary mask)"
# Create a stats-only design.fsf file
local DESIGN_FILE="${OUTPUT_DIR}/design_stats_only.fsf"
echo "Creating stats-only FEAT design file: $DESIGN_FILE"
cat > "$DESIGN_FILE" << EOF
# FEAT version number
set fmri(version) 6.00
# Analysis level
set fmri(level) 1
# FEAT directory
set fmri(outputdir) "${OUTPUT_DIR}/stats_only.feat"
# Input data
set feat_files(1) "$FUNC_DATA"
# TR(s)
set fmri(tr) $TR
# Total volumes
set fmri(npts) $NVOLS
# Delete volumes
set fmri(ndelete) 0
# Pre-stats
# Skip all preprocessing
set fmri(preprocessing) 0
# Brain/background threshold
set fmri(brain_thresh) 0 # Doesn't matter with a provided mask
# Use alternative mask
set fmri(alternative_mask) 1
set fmri(alternative_mask_file) "$MASK_FILE"
# Stats mode - using FILM
set fmri(st) 1
# Enable prewhitening for better statistical accuracy
set fmri(prewhiten_yn) 1
# No motion correction
set fmri(mc) 0
set fmri(sh_yn) 0
# No slice timing correction
set fmri(st) 0
# No BET
set fmri(bet_yn) 0
# No spatial smoothing
set fmri(smooth) 0
# No temporal filtering
set fmri(temphp_yn) 0
set fmri(templp_yn) 0
# Add confound EVs from motion parameters
set fmri(confoundevs) 1
set confoundev_files(1) "$CONFOUNDS_FILE"
# EV 1: Fix
set fmri(evtitle1) "Fix"
set fmri(shape1) 3
set fmri(convolve1) 0
set fmri(custom1) "${TIMING_DIR}/timing_file_fix.txt"
# EV 2: Motor
set fmri(evtitle2) "Motor"
set fmri(shape2) 3
set fmri(convolve2) 3
set fmri(custom2) "${TIMING_DIR}/timing_file_motor.txt"
# EV 3: A
set fmri(evtitle3) "A"
set fmri(shape3) 3
set fmri(convolve3) 3
set fmri(custom3) "${TIMING_DIR}/timing_file_a.txt"
# EV 4: B
set fmri(evtitle4) "B"
set fmri(shape4) 3
set fmri(convolve4) 3
set fmri(custom4) "${TIMING_DIR}/timing_file_b.txt"
# Number of EVs
set fmri(evs_orig) 4
set fmri(evs_real) 4
set fmri(ncon_real) 7
set fmri(nftests_real) 0
# Contrast 1: Motor - Fix
set fmri(conname_real.1) "motor-fix"
set fmri(con_real1.1) 0
set fmri(con_real1.2) 1
set fmri(con_real1.3) 0
set fmri(con_real1.4) 0
# Contrast 2: A - Fix
set fmri(conname_real.2) "a-fix"
set fmri(con_real2.1) 0
set fmri(con_real2.2) 0
set fmri(con_real2.3) 1
set fmri(con_real2.4) 0
# Contrast 3: B - Fix
set fmri(conname_real.3) "b-fix"
set fmri(con_real3.1) 0
set fmri(con_real3.2) 0
set fmri(con_real3.3) 0
set fmri(con_real3.4) 1
# Contrast 4: A - B
set fmri(conname_real.4) "a-b"
set fmri(con_real4.1) 0
set fmri(con_real4.2) 0
set fmri(con_real4.3) 1
set fmri(con_real4.4) -1
# Contrast 5: B - A
set fmri(conname_real.5) "b-a"
set fmri(con_real5.1) 0
set fmri(con_real5.2) 0
set fmri(con_real5.3) -1
set fmri(con_real5.4) 1
# Contrast 6: (Motor + A + B) - 3*Fix
set fmri(conname_real.6) "task-fix"
set fmri(con_real6.1) -3
set fmri(con_real6.2) 1
set fmri(con_real6.3) 1
set fmri(con_real6.4) 1
# Contrast 7: (A + B) - 2*Motor
set fmri(conname_real.7) "cogtask-motor"
set fmri(con_real7.1) 0
set fmri(con_real7.2) -2
set fmri(con_real7.3) 1
set fmri(con_real7.4) 1
# Don't use registration (data already in standard space)
set fmri(reg_yn) 0
# Don't run non-linear reg
set fmri(nonlinear_yn) 0
# Z threshold
set fmri(z_thresh) $Z_THRESH
# Z threshold type: 1 = uncorrected, 2 = voxel, 3 = cluster
set fmri(thresh) 3
# Cluster p-threshold
set fmri(prob_thresh) $CLUSTER_P_THRESH
# Minimum cluster size in voxels
set fmri(threshmask) ""
set fmri(minclustersize) 0
# Full model setup
set fmri(mixed_yn) 1
set fmri(factmix) 1
set fmri(groupmem.1) 1
set fmri(withinmix) standard
EOF
echo "Running FEAT with command-line mode for $SUBJECT_ID..."
# Use feat_model to generate the model
feat_model "$OUTPUT_DIR/stats_only"
if [ $? -ne 0 ]; then
echo "ERROR: feat_model failed for $SUBJECT_ID"
return 1
fi
# Pre-create the output directory
mkdir -p "${OUTPUT_DIR}/stats_only.feat/stats"
# Run FEAT's film_gls directly
echo "Running film_gls..."
film_gls --in="${FUNC_DATA}" \
--rn="${OUTPUT_DIR}/stats_only.feat" \
--pd="${OUTPUT_DIR}/stats_only.feat/design.mat" \
--tcon="${OUTPUT_DIR}/stats_only.feat/design.con" \
--mode=1 \
--out="${OUTPUT_DIR}/stats_only.feat/stats" \
--mask="${MASK_FILE}" \
--epith=1000 \
--con_index=1 \
--con_name=motor-fix \
--con_index=2 \
--con_name=a-fix \
--con_index=3 \
--con_name=b-fix \
--con_index=4 \
--con_name=a-b \
--con_index=5 \
--con_name=b-a \
--con_index=6 \
--con_name=task-fix \
--con_index=7 \
--con_name=cogtask-motor
if [ $? -ne 0 ]; then
echo "ERROR: film_gls failed for $SUBJECT_ID"
return 1
fi
# Run FEAT's cluster
echo "Running cluster thresholding..."
for i in {1..7}; do
cluster --in="${OUTPUT_DIR}/stats_only.feat/stats/zstat${i}" \
--thresh=$Z_THRESH \
--pthresh=$CLUSTER_P_THRESH \
--oindex="${OUTPUT_DIR}/stats_only.feat/cluster_mask_zstat${i}" \
--olmax="${OUTPUT_DIR}/stats_only.feat/lmax_zstat${i}.txt" \
--mask="${MASK_FILE}"
done
if [ -f "${OUTPUT_DIR}/stats_only.feat/stats/cope1.nii.gz" ]; then
echo "FEAT analysis complete for $SUBJECT_ID. Results are in: ${OUTPUT_DIR}/stats_only.feat"
return 0
else
echo "ERROR: FEAT analysis failed for $SUBJECT_ID"
return 1
fi
}
# Create list for valid subjects
valid_subjects_file="${OUTPUT_BASE_DIR}/valid_feat_dirs.txt"
> "$valid_subjects_file"
# Process subjects 1-10
successful=0
failed=0
for i in {1..10}; do
if process_subject $i; then
echo "${OUTPUT_BASE_DIR}/sub-${i}/stats_only.feat" >> "$valid_subjects_file"
((successful++))
else
((failed++))
fi
echo ""
done
# Function to create group analysis design file for a specific contrast
create_group_design() {
local contrast_num=$1
local contrast_name=$2
echo "Creating group analysis design file for contrast $contrast_num: $contrast_name..."
local group_design="${OUTPUT_BASE_DIR}/group_design_contrast${contrast_num}.fsf"
# Create basic higher-level design file
cat > "$group_design" << EOF
# FEAT version number
set fmri(version) 6.00
# Higher-level analysis
set fmri(level) 2
# FEAT directory
set fmri(outputdir) "${OUTPUT_BASE_DIR}/group_contrast${contrast_num}_${contrast_name}.gfeat"
# Number of inputs
set fmri(npts) $successful
# Mixed effects: 3 = FLAME 1
set fmri(mixed_yn) 3
# Higher-level model
set fmri(pluginname) "flame1"
# Use lower-level copes
set fmri(forcehigherlevel_yn) 1
# Add confound EVs text file
set fmri(confoundevs) 0
# Don't add FE stats
set fmri(fe1_yn) 0
# Z threshold
set fmri(z_thresh) $Z_THRESH
# Z threshold type: 1 = uncorrected, 2 = voxel, 3 = cluster
set fmri(thresh) 3
# Cluster p-threshold
set fmri(prob_thresh) $CLUSTER_P_THRESH
# Minimum cluster size in voxels
set fmri(threshmask) ""
set fmri(minclustersize) 0
# Motion correction
set fmri(mc) 0
# Which contrast
set fmri(conindex) $contrast_num
# Use one-sample group mean
set fmri(con_mode) 1
set fmri(con_mode1) 1
# Design matrix directory
set fmri(evs_orig) 1
set fmri(evs_real) 1
set fmri(evtitle1) "Group_Mean"
# Group membership for input 1
set fmri(groupmem.1) 1
# Input FEAT directories
EOF
# Add all subject FEAT directories
subj_count=1
while read -r feat_dir; do
echo "set feat_files($subj_count) \"$feat_dir\"" >> "$group_design"
((subj_count++))
done < "$valid_subjects_file"
echo "Group analysis design file created: $group_design"
return 0
}
# If we have enough successful subjects, create group analysis design files
if [ $successful -ge 2 ]; then
echo "Creating group analysis design files for all contrasts..."
# Define contrast names for better file naming
CONTRAST_NAMES=("" "motor-fix" "a-fix" "b-fix" "a-b" "b-a" "task-fix" "cogtask-motor")
# Create design files for all contrasts
for ((i=1; i<=7; i++)); do
create_group_design $i "${CONTRAST_NAMES[$i]}"
done
# Create a single script to run all group analyses
group_run_script="${OUTPUT_BASE_DIR}/run_all_group_analyses.sh"
echo "#!/bin/bash" > "$group_run_script"
echo "" >> "$group_run_script"
echo "# Script to run all group analyses" >> "$group_run_script"
echo "# Load FSL" >> "$group_run_script"
echo "module load fsl/6.0.3-cuda9.1" >> "$group_run_script"
echo "" >> "$group_run_script"
for ((i=1; i<=7; i++)); do
echo "echo \"Running group analysis for contrast $i: ${CONTRAST_NAMES[$i]}...\"" >> "$group_run_script"
echo "feat -d ${OUTPUT_BASE_DIR}/group_design_contrast${i}.fsf" >> "$group_run_script"
echo "" >> "$group_run_script"
done
chmod +x "$group_run_script"
echo "Created script to run all group analyses: $group_run_script"
fi
# Summary
echo "========================================================="
echo "Analysis Summary:"
echo "Successful subjects: $successful"
echo "Failed subjects: $failed"
echo "List of valid FEAT directories saved to: $valid_subjects_file"
echo ""
if [ $successful -ge 2 ]; then
echo "Group analysis design files created for all contrasts"
echo "To run all group analyses: ${OUTPUT_BASE_DIR}/run_all_group_analyses.sh"
echo "Or run individual contrasts with: feat -d ${OUTPUT_BASE_DIR}/group_design_contrast<N>.fsf"
else
echo "Not enough successful subjects for group analysis"
fi
echo "========================================================="
Version:
Environment (Docker, Singularity / Apptainer, custom installation):
Data formatted according to a validatable standard? Please provide the output of the validator:
PASTE VALIDATOR OUTPUT HERE
Relevant log outputs (up to 20 lines):
PASTE LOG OUTPUT HERE