Revision 6e2fe5e4e8b676aff92cbdc29e30bbd6ab613fac authored by Timothy Brown on 21 March 2014, 21:19:28 UTC, committed by Timothy Brown on 21 March 2014, 21:19:28 UTC
1 parent 49de93a
TaskfMRILevel3.sh
#!/bin/bash
#set -x
# Authors: Michael Harms, Matthew Glasser, Sachin Dixit
usage() {
{
echo "Usage: $0 --path=<> --subjectlist=<> --resultsfolder=<> --analysisname=<> --lvl3fsf=<> --lvl2task=<> --lvl2fsf=<> --finalsmoothingFWHM=<> --temporalfilter=<> --regname=<> --analysistype=<> --contrastlist=<>"
echo
echo "--path=<StudyFolder>"
echo
echo "--subjectlist=<SubjectList>"
echo " List of subject IDs, separated by @ symbol (without spaces)"
echo
echo "--resultsfolder=<ResultsFolder>"
echo " Directory name for outputs of this script"
echo
echo "--analysisname=<AnalysisName>"
echo " Used as an initial prefix in some file naming"
echo
echo "--lvl3fsf=<LevelThreeFsf>"
echo " Specification of EVs, Contrasts, and F-tests, in FSL's fsf format"
echo " Does not need to specify any inputs files."
echo " However, the order of rows in the design matrix are assumed to "
echo " match the order of subjects in SubjectList."
echo " Can be created using FSL's Glm GUI"
echo
echo "--lvl2task=<LevelTwofMRIName>"
echo "--lvl2fsf=<LevelTwofsfName>"
echo "--finalsmoothingFWHM=<FinalSmoothingFWHM>"
echo "--temporalfilter=<TemporalFilter>"
echo "--regname=<RegName>"
echo " Together, these define aspects of the Level1/2 analysis,"
echo " and the location of the Level2 input directories for each subject"
echo " e.g., \${LevelTwofMRIName}/\${LevelTwofsfName}_hp\${TemporalFilter}_s\${FinalSmoothingFWHM}_level2_\${RegName}.feat"
echo
echo "--analysistype=<GRAYORD,VOLUME, or BOTH>"
echo
echo "--contrastlist=<ContrastList>"
echo " Use ALL to automatically create Level3 results for each of the Level2 contrasts"
echo " Otherwise, use a list of numbers, separated by @ symbol (without spaces)"
echo " to process just those specific Level2 contrasts"
echo " e.g., --contrastlist=1@6@8"
echo " would process just contrasts 1, 6, and 8 from Level2"
echo
} >&2
exit 7
}
# function for parsing options
getopt1() {
sopt="$1"
shift 1
for fn in $@ ; do
if [ `echo $fn | grep -- "^${sopt}=" | wc -w` -gt 0 ] ; then
echo $fn | sed "s/^${sopt}=//"
return 0
fi
done
}
defaultopt() {
echo $1
}
# Just give usage if no arguments specified
if [ $# -eq 0 ] ; then usage; exit 0; fi
StudyFolder=`getopt1 "--path" $@`
SubjectList=`getopt1 "--subjectlist" $@`
ResultsFolder=`getopt1 "--resultsfolder" $@`
AnalysisName=`getopt1 "--analysisname" $@` # Used as initial prefix in some file naming.
LevelThreeFsf=`getopt1 "--lvl3fsf" $@` # Needs to specify the EVs, Contrasts, and F-tests. Does NOT need to specify any inputs.
# However, order of inputs (rows) MUST correspond to order used in $SubjectList.
# Can be created using "Glm" GUI.
LevelTwofMRIName=`getopt1 "--lvl2task" $@`
LevelTwofsfName=`getopt1 "--lvl2fsf" $@`
FinalSmoothingFWHM=`getopt1 "--finalsmoothingFWHM" $@`
TemporalFilter=`getopt1 "--temporalfilter" $@`
AnalysisType=`getopt1 "--analysistype" $@`
RegName=`getopt1 "--regname" $@`
ContrastListIn=`getopt1 "--contrastlist" $@`
### M.P.Harms changes, Oct-Dec 2013 ###
# Eliminate copying of Lev2 data -- use sym links for Volume analysis, and just convert CIFTI directly for Grayordinates.
# For Grayordinates, convert (CIFTI->NIFTI) only the specific lower-level files that are necessary for 'flameo'.
# Added "--fc" option to 'flameo' to compute F-tests.
# Extended code to allow processing of only specific Lev2 copes (via ContrastListIn argument).
# Allowed for a Volume only analysis.
# Consolidated common code outside of 'for' loops.
# Added check to confirm that Lev2 contrasts are the same across subjects.
# Added variables to permit deletion of non-essential files.
# Extended code that generates files for viewing to flexibly handle copes, zstats, and zfstats,
# and to handle more than 1 contrast in the Level3 analysis.
# Changed directory structure to be a bit more "Feat-like" [i.e., added 'stats' directory to store direct output
# of 'flameo', thereby creating a directory level (copeX.feat) for future post-flameo processing, such as FDR,
# randomise, or cluster-corrected statistical images].
# Split Grayordinate and Volume analyses into separate output gfeat directories for better segregation and flexibility.
# (Allows one to run a Volume analysis after a Grayordinate analysis, without disturbing the latter).
# Various changes to help with readability (e.g., extract file names into variables).
# To do (?):
# 1) Add capability to go back and add certain contrasts while integrating into the already existing data
# 2) Rework .dtseries.nii, .dscalar.nii conversions if workbench develops easier approaches
# 3) Add creation of a Lev3Contrasts.txt file (describing the Lev3 contrasts).
##Naming Conventions
CommonAtlasFolder="${ResultsFolder}/MNINonLinear"
CommonResultsFolder="${CommonAtlasFolder}/Results"
##Set up some things
# Note that all lists should be space separated lists. NOT defined as arrays.
SubjectList=`echo $SubjectList | sed 's/@/ /g'`
NumSubjects=`echo ${SubjectList} | wc -w`
SmoothingString="_s${FinalSmoothingFWHM}"
TemporalFilterString="_hp""$TemporalFilter"
if [ ! "${RegName}" = "NONE" ] ; then
RegString="_${RegName}"
else
RegString=""
fi
##Hidden options not available via command line arguments
DeleteIntermediates="YES" #Set to "NO" to preserve intermediate (CIFTI/NIFTI conversion) files (for debugging)
DeleteMergedFlameoInputs="YES" #Set to "NO" to preserve the merged Lev2 file files (for debugging)
DeleteSingleContrastDscalars="YES" #Set to "YES" to delete the single contrast dscalar files,
# leaving only the aggregated composite containing all contrasts.
DscalarMeasureList="cope zstat zfstat" #List of measures for which to aggregate across contrasts
# for convenient viewing in Workbench.
#Result will be one dscalar file for each measure, containing
# as its COL dimension the Lev2 contrasts specified in ContrastListIn.
#Can set to empty to avoid aggregation across contrasts.
StartTime=`date`
echo $StartTime
LevelTwoFEATDirSTRING=""
for Subject in $SubjectList ; do
AtlasFolder="${StudyFolder}/${Subject}/MNINonLinear"
ResultsFolder="${AtlasFolder}/Results"
LevelTwoFEATDir="${ResultsFolder}/${LevelTwofMRIName}/${LevelTwofsfName}${TemporalFilterString}${SmoothingString}_level2${RegString}.feat"
if [ -d ${LevelTwoFEATDir} ] ; then
LevelTwoFEATDirSTRING="${LevelTwoFEATDirSTRING} ${LevelTwoFEATDir}"
else
echo "ERROR: ${LevelTwoFEATDir} does not exist for ${Subject}"
exit -1
fi
done
FirstFolder=`echo $LevelTwoFEATDirSTRING | cut -d " " -f 1`
ContrastNames=`cat ${FirstFolder}/Contrasts.txt`
#Set up ContrastList
if [ "${ContrastListIn}" = "ALL" ] ; then
NumContrasts=`echo ${ContrastNames} | wc -w`
j=1
while [ $j -le ${NumContrasts} ] ; do
ContrastList="${ContrastList} $j"
j=$(($j+1))
done
else
ContrastList=`echo $ContrastListIn | sed 's/@/ /g'`
fi
LevelThreeFEATDirGray="${CommonResultsFolder}/${LevelTwofMRIName}/${LevelTwofsfName}${TemporalFilterString}${SmoothingString}_level3${RegString}.gfeat"
LevelThreeFEATDirVol="${CommonResultsFolder}/${LevelTwofMRIName}/${LevelTwofsfName}${TemporalFilterString}${SmoothingString}_level3vol${RegString}.gfeat"
DIR=`pwd`
#Loop over Grayordinates and Standard Volume (if requested) Level 2 Analyses
if [ "${AnalysisType}" = "BOTH" ] ; then
Analyses="GrayordinatesStats StandardVolumeStats"
elif [ "${AnalysisType}" = "VOLUME" ] ; then
Analyses="StandardVolumeStats"
else
Analyses="GrayordinatesStats" # Default to Grayordinate analysis only
fi
for Analysis in ${Analyses} ; do
#Set LevelThreeFEATDir according to Analysis type
if [ "$Analysis" = "GrayordinatesStats" ] ; then
LevelThreeFEATDir=${LevelThreeFEATDirGray}
elif [ "$Analysis" = "StandardVolumeStats" ] ; then
LevelThreeFEATDir=${LevelThreeFEATDirVol}
else
echo "ERROR: $Analysis not a valid analysis mode"
exit -1
fi
echo -e "\n----- ANALYSIS = $Analysis -----"
if [ -d ${LevelThreeFEATDir} ] ; then
rm -r ${LevelThreeFEATDir}
fi
#Define directory where the copeX.feat directories (corresponding to each Lev2 contrast) will go
# Since we've split Grayordinate and Volume analyses into separate root gfeat directories (above),
# we will just use LevelThreeFEATDir itself. (This yields a directory structure closer to FEAT output).
LevelThreeFEATDirCopes=${LevelThreeFEATDir}
# If Grayordinate and Volume analyses are to be part of the same LevelThreeFEATDir (previous implementation)
# then can easily revert to that by using the following definition instead:
##LevelThreeFEATDirCopes=${LevelThreeFEATDir}/${Analysis}
# (Note that if you use the above line, must make a similar change in the section "Generate Files for
# Workbench viewing" as well).
mkdir -p ${LevelThreeFEATDirCopes}
#Make design files
cat ${LevelThreeFsf} > ${LevelThreeFEATDir}/design.fsf
cd ${LevelThreeFEATDir}
feat_model ${LevelThreeFEATDir}/design
cd $DIR
## --- BEGIN PREP SECTION --- ##
# Prepare convenient directory structure for merging lower level inputs
# And convert CIFTI to NIFTI if Grayordinates analysis
for i in ${ContrastList} ; do
Contrast=`echo $ContrastNames | cut -d " " -f $i`
echo "COPE $i, $Contrast, Preparing inputs, `date`"
j=1
for Subject in ${SubjectList} ; do
if (( $j % 20 == 0 )) ; then
echo " Subject $j/$NumSubjects"
fi
LevelTwoFEATDir=`echo ${LevelTwoFEATDirSTRING} | cut -d " " -f $j`
#Confirm that all the Lev2 inputs have the same contrasts, otherwise we have a problem
diff ${FirstFolder}/Contrasts.txt ${LevelTwoFEATDir}/Contrasts.txt > /dev/null
if [ $? -ne 0 ] ; then
echo "ERROR: Contrasts.txt in ${LevelTwoFEATDir} doesn't match that in ${FirstFolder}"
exit -1
fi
## Subsection specific to Grayordinates analysis
if [ "$Analysis" = "GrayordinatesStats" ] ; then
mkdir -p ${LevelThreeFEATDirCopes}/${i}/${j}
## Need to convert 4 files back to NIFTI for use in FLAMEO
for File in {mask,cope1,varcope1,tdof_t1} ; do
cifti_in=${LevelTwoFEATDir}/${Analysis}/cope${i}.feat/${File}.dtseries.nii
cifti_out=${LevelThreeFEATDirCopes}/${i}/${j}/${File}.nii.gz
if [ ! -e ${cifti_in} ] ; then
echo "ERROR: ${cifti_in} does not exist"
exit -1
fi
${CARET7DIR}/wb_command -cifti-convert -to-nifti ${cifti_in} ${cifti_out}
done
## Subsection specific to Volume analysis
elif [ "$Analysis" = "StandardVolumeStats" ] ; then
mkdir -p ${LevelThreeFEATDirCopes}/${i}
## For StandardVolumeStats, just create symbolic links to original copeX.feat directories
copedir=${LevelTwoFEATDir}/${Analysis}/cope${i}.feat
if [ ! -e ${copedir} ] ; then
echo "ERROR: ${copedir} does not exist"
exit -1
fi
ln -s ${copedir} ${LevelThreeFEATDirCopes}/${i}/${j}
else
echo "ERROR: $Analysis not a valid analysis mode"
exit -1
fi ##End of specific gray and vol subsections
j=$(($j+1))
done # Subject loop
done # ContrastList loop
## --- END PREP SECTION --- ##
## --- BEGIN FLAMEO SECTION --- ##
# Merge copes, varcopes, masks, and tdof_t1s, and run 3rd level analysis
# Because of how we prep'ed above, same code applies here for both Grayordinate and Volume analyses
echo -e "\nMerging inputs and running FLAMEO"
ExtraArgs=""
if [ -e ${LevelThreeFEATDir}/design.fts ] ; then
ExtraArgs="$ExtraArgs --fc=${LevelThreeFEATDir}/design.fts"
fi
for i in ${ContrastList} ; do
MASKMERGE=""
COPEMERGE=""
VARCOPEMERGE=""
DOFMERGE=""
j=1
while [ $j -le ${NumSubjects} ] ; do
MASKMERGE="${MASKMERGE} ${LevelThreeFEATDirCopes}/${i}/${j}/mask.nii.gz"
COPEMERGE="${COPEMERGE} ${LevelThreeFEATDirCopes}/${i}/${j}/cope1.nii.gz"
VARCOPEMERGE="${VARCOPEMERGE} ${LevelThreeFEATDirCopes}/${i}/${j}/varcope1.nii.gz"
DOFMERGE="${DOFMERGE} ${LevelThreeFEATDirCopes}/${i}/${j}/tdof_t1.nii.gz"
j=$(($j+1))
done
copedir="${LevelThreeFEATDirCopes}/cope${i}.feat"
mkdir -p ${copedir}
cd ${copedir}
suffix="_lev2data" #Suffix to distinguish the merged lev2 files
mergedcope=cope${i}${suffix}
mergedvarcope=varcope${i}${suffix}
mergedtdof=tdof_t1_${i}${suffix}
fslmerge -t mask${i} $MASKMERGE
fslmaths mask${i} -Tmin mask${i}
fslmerge -t $mergedcope $COPEMERGE
fslmaths $mergedcope -mas mask${i} $mergedcope
fslmerge -t $mergedvarcope $VARCOPEMERGE
fslmaths $mergedvarcope -mas mask${i} $mergedvarcope
fslmerge -t $mergedtdof $DOFMERGE
fslmaths $mergedtdof -mas mask${i}.nii.gz $mergedtdof
flameo --cope=$mergedcope --vc=$mergedvarcope --dvc=$mergedtdof --mask=mask${i} --ld=stats --dm=${LevelThreeFEATDir}/design.mat --cs=${LevelThreeFEATDir}/design.grp --tc=${LevelThreeFEATDir}/design.con ${ExtraArgs} --runmode=flame1 --outputdof
# Cleanup
if [ "${DeleteMergedFlameoInputs}" = "YES" ] ; then
rm -r mask${i}.nii.gz ${mergedcope}.nii.gz ${mergedvarcope}.nii.gz ${mergedtdof}.nii.gz
fi
if [ "${DeleteIntermediates}" = "YES" ] ; then
rm -r ${LevelThreeFEATDirCopes}/${i}
fi
cd $DIR
done
echo -e "\nDone FLAMEO\n"
## --- END FLAMEO SECTION --- ##
## --- BEGIN POST-FLAMEO CONVERSIONS --- ##
# Convert NIFTI file back to CIFTI; only relevant for Grayordinate analysis
if [ "$Analysis" = "GrayordinatesStats" ] ; then
cd ${LevelThreeFEATDirCopes}
Files=`ls | grep .nii.gz | cut -d "." -f 1`
cd $DIR
for File in $Files ; do
nifti_in=${LevelThreeFEATDirCopes}/${File}.nii.gz
cifti_template=${LevelTwoFEATDir}/${Analysis}/cope1.feat/pe1.dtseries.nii
cifti_out=${LevelThreeFEATDirCopes}/${File}.dtseries.nii
${CARET7DIR}/wb_command -cifti-convert -from-nifti ${nifti_in} ${cifti_template} ${cifti_out} -reset-timepoints 1 1
if [ "${DeleteIntermediates}" = "YES" ] ; then
rm ${LevelThreeFEATDirCopes}/${File}.nii.gz
fi
done
for i in ${ContrastList} ; do
echo "COPE $i, Converting NIFTI->CIFTI, `date`"
cd ${LevelThreeFEATDirCopes}/cope${i}.feat/stats
Files=`ls | grep .nii.gz | cut -d "." -f 1`
cd $DIR
for File in $Files ; do
nifti_in=${LevelThreeFEATDirCopes}/cope${i}.feat/stats/${File}.nii.gz
cifti_template=${LevelTwoFEATDir}/${Analysis}/cope${i}.feat/pe1.dtseries.nii
cifti_out=${LevelThreeFEATDirCopes}/cope${i}.feat/stats/${File}.dtseries.nii
${CARET7DIR}/wb_command -cifti-convert -from-nifti ${nifti_in} ${cifti_template} ${cifti_out} -reset-timepoints 1 1
if [ "${DeleteIntermediates}" = "YES" ] ; then
rm ${LevelThreeFEATDirCopes}/cope${i}.feat/stats/${File}.nii.gz
fi
done
done
fi ##END of NIFTI->CIFTI conversion for Grayordinates analysis
## --- END POST-FLAMEO CONVERSIONS --- ##
done # for Analysis in ${Analyses} ; do
### --- Generate Files for Workbench viewing --- ###
echo -e "\n----- Generating files for viewing -----"
for Analysis in ${Analyses} ; do
#Set LevelThreeFEATDir according to Analysis type
if [ "$Analysis" = "GrayordinatesStats" ] ; then
LevelThreeFEATDir=${LevelThreeFEATDirGray}
elif [ "$Analysis" = "StandardVolumeStats" ] ; then
LevelThreeFEATDir=${LevelThreeFEATDirVol}
else
echo "ERROR: $Analysis not a valid analysis mode"
exit -1
fi
# See comment above regarding LevelThreeFEATDirCopes
LevelThreeFEATDirCopes=${LevelThreeFEATDir}
for MeasureType in ${DscalarMeasureList} ; do
# Create a list of all possible unique files for each measure (i.e., zstat1, zstat2, ..., zstatN if MeasureType="zstat")
cd ${LevelThreeFEATDirCopes}
StatPrefixes=`ls -1 cope*.feat/stats/${MeasureType}* 2> /dev/null`
if [ ${#StatPrefixes} -gt 0 ] ; then
StatPrefixes=`echo $StatPrefixes | xargs -n 1 basename | cut -d "." -f 1 | sort -u`
fi
cd $DIR
for statistic in ${StatPrefixes} ; do
MergeSTRING=""
if [ -e ${LevelThreeFEATDir}/Contrasts.txt ] ; then
rm ${LevelThreeFEATDir}/Contrasts.txt
rm -f ${LevelThreeFEATDir}/Contrasttemp.txt
fi
for i in ${ContrastList} ; do
Contrast=`echo $ContrastNames | cut -d " " -f $i`
echo "COPE $i, $Contrast, $statistic, $Analysis"
prefix="${AnalysisName}_${LevelTwofsfName}_level3_${statistic}_${Contrast}${TemporalFilterString}${SmoothingString}${RegString}"
echo ${prefix} >> ${LevelThreeFEATDir}/Contrasttemp.txt
echo ${Contrast} >> ${LevelThreeFEATDir}/Contrasts.txt
## Subsection specific to Grayordinates analysis
if [ "$Analysis" = "GrayordinatesStats" ] ; then
input=${LevelThreeFEATDirCopes}/cope${i}.feat/stats/${statistic}.dtseries.nii
if [ ! -e ${input} ] ; then
echo "ERROR: ${input} does not exist"
exit -1
fi
output=${LevelThreeFEATDir}/${prefix}.dscalar.nii
${CARET7DIR}/wb_command -cifti-convert-to-scalar ${input} ROW ${output} -name-file ${LevelThreeFEATDir}/Contrasttemp.txt
MergeSTRING=`echo "${MergeSTRING} -cifti ${output}"`
## Subsection specific to Volume analysis
elif [ "$Analysis" = "StandardVolumeStats" ] ; then
label_list=${LevelThreeFEATDir}/wbtemp.txt
echo "OTHER" >> ${label_list}
echo "1 255 255 255 255" >> ${label_list}
volume_to_label=${LevelThreeFEATDirCopes}/cope${i}.feat/stats/mask.nii.gz
labeled_volume=${LevelThreeFEATDirCopes}/cope${i}.feat/stats/masktmp.nii.gz
${CARET7DIR}/wb_command -volume-label-import ${volume_to_label} ${label_list} ${labeled_volume} -discard-others -unlabeled-value 0
rm ${label_list}
prefix=${AnalysisName}_${LevelTwofsfName}_level3vol_${statistic}_${Contrast}${TemporalFilterString}${SmoothingString}${RegString}
input=${LevelThreeFEATDirCopes}/cope${i}.feat/stats/${statistic}.nii.gz
if [ ! -e ${input} ] ; then
echo "ERROR: ${input} does not exist"
exit -1
fi
outputdtseries=${LevelThreeFEATDir}/${prefix}.dtseries.nii
outputdscalar=${LevelThreeFEATDir}/${prefix}.dscalar.nii
${CARET7DIR}/wb_command -cifti-create-dense-timeseries ${outputdtseries} -volume ${input} ${labeled_volume} -timestep 1 -timestart 1
${CARET7DIR}/wb_command -cifti-convert-to-scalar ${outputdtseries} ROW ${outputdscalar} -name-file ${LevelThreeFEATDir}/Contrasttemp.txt
rm ${outputdtseries} ${labeled_volume}
MergeSTRING=`echo "${MergeSTRING} -cifti ${outputdscalar}"`
else
echo "ERROR: $Analysis not a valid analysis mode"
exit -1
fi
rm ${LevelThreeFEATDir}/Contrasttemp.txt
done # contrast loop
# Merge across contrasts for a given statistic
if [ "$Analysis" = "GrayordinatesStats" ] ; then
cifti_merge_out=${LevelThreeFEATDir}/${AnalysisName}_${LevelTwofsfName}_level3_${statistic}${TemporalFilterString}${SmoothingString}${RegString}.dscalar.nii
elif [ "$Analysis" = "StandardVolumeStats" ] ; then
cifti_merge_out=${LevelThreeFEATDir}/${AnalysisName}_${LevelTwofsfName}_level3vol_${statistic}${TemporalFilterString}${SmoothingString}.dscalar.nii
fi
${CARET7DIR}/wb_command -cifti-merge ${cifti_merge_out} ${MergeSTRING}
if [ "${DeleteSingleContrastDscalars}" = "YES" ] ; then
FilesToDelete=`echo ${MergeSTRING} | sed 's/-cifti//g'`
rm ${FilesToDelete}
fi
done # statistic loop
done # MeasureType loop
done # Analysis loop
FinishTime=`date`
echo "Start time: ${StartTime}"
echo "Finish time: ${FinishTime}"
exit
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...