diff --git a/Examples/Scripts/RunPFMpipelineFullRun.sh b/Examples/Scripts/RunPFMpipelineFullRun.sh new file mode 100755 index 000000000..44ee1b93a --- /dev/null +++ b/Examples/Scripts/RunPFMpipelineFullRun.sh @@ -0,0 +1,248 @@ +#!/bin/bash + +set -eu + +# This is an example script to run the full PFM postprocessing pipeline +# Steps involved: +# 1. RunPROFUMO - Run PROFUMO analysis +# 2. PostPROFUMO - Create time courses, spectra, and maps from PFM results +# 3. RSNRegression - Run RSN regression on PFM data for dual regression +# 4. GroupPFMs - Generate group-level statistics and averages +# +# Please make sure that PROFUMO, ICA-FIX, MSMAll and MakeAverageDataset are done properly +# matching the input arguments before running this PFM pipeline + +get_options() { + local scriptName=$(basename "$0") + local arguments=("$@") + + # initialize variables + StudyFolder="${HOME}/data/HCPpipelines_ExampleData" + Subjlist="100610@102311" + EnvironmentScript="${HOME}/projects/HCPpipelines/Examples/Scripts/SetUpHCPPipeline.sh" + GroupAverageName="S1200_MSMAll7T175" + + RegName="MSMAll" + MatlabMode=1 + RunLocal=0 + QUEUE="matlabparallelhigh.q" + + # parse arguments + local index argument + + for ((index = 0; index < ${#arguments[@]}; ++index)) + do + argument="${arguments[index]}" + + case "$argument" in + --StudyFolder=*) + StudyFolder="${argument#*=}" + ;; + --Subject=*) + Subjlist="${argument#*=}" + ;; + --EnvironmentScript=*) + EnvironmentScript="${argument#*=}" + ;; + --GroupAverageName=*) + GroupAverageName="${argument#*=}" + ;; + --RegName=*) + RegName="${argument#*=}" + ;; + --MatlabMode=*) + MatlabMode="${argument#*=}" + ;; + *) + echo "ERROR: Unrecognized Option: ${argument}" + exit 1 + ;; + esac + done + + # check required parameters + if [[ "$StudyFolder" == "" ]] + then + echo "ERROR: StudyFolder not specified" + exit 1 + fi + + if [[ "$Subjlist" == "" ]] + then + echo "ERROR: Subjlist not specified" + exit 1 + fi + + if [[ "$EnvironmentScript" == "" ]] + then + echo "ERROR: EnvironmentScript not specified" + exit 1 + fi + + if [[ "$GroupAverageName" == "" ]] + then + echo "ERROR: GroupAverageName not specified" + exit 1 + fi + + # if [[ "$RegName" == "" ]] + # then + # echo "ERROR: RegName not specified" + # exit 1 + # fi + + if [[ "$MatlabMode" == "" ]] + then + echo "ERROR: MatlabMode not specified" + exit 1 + fi + + # report options + echo "-- ${scriptName}: Specified Command-Line Options: -- Start --" + echo " StudyFolder: ${StudyFolder}" + echo " Subjlist: ${Subjlist}" + echo " EnvironmentScript: ${EnvironmentScript}" + echo " GroupAverageName: ${GroupAverageName}" + echo " RegName: ${RegName}" + echo " MatlabMode: ${MatlabMode}" + echo "-- ${scriptName}: Specified Command-Line Options: -- End --" +} + +# get command line options +get_options "$@" + +# set up pipeline environment variables and software +source "${EnvironmentScript}" + +if ((RunLocal)) || [[ "$QUEUE" == "" ]]; then + echo "running locally" + queuing_command=("$HCPPIPEDIR"/global/scripts/captureoutput.sh) +else + echo "queueing with fsl_sub to $QUEUE" + queuing_command=("$FSLDIR/bin/fsl_sub" -q "$QUEUE") +fi + +# Download the PROFUMO Singularity image from the following link and place it in the PFM folder, +# or change the path below to point to your own copy of the image +# https://balsa.wustl.edu/myelin/download?dirName=public&filepath=profumo_v2.sif +ProfumoSingularity="$HCPPIPEDIR/PFM/profumo_v2.sif" + +# general settings +# set the start step beginning from RunPROFUMO which is by default the first step +StartStep="RunPROFUMO" +StopStep="GroupPFMs" +NumWishart="6" +KeepWishartFiles="NO" + +# set how many subjects to do in parallel (local, not cluster-distributed) during RSN regression, defaults to all detected physical cores, '-1' +parLimit=-1 + +# general inputs +fMRINames="rfMRI_REST1_LR@rfMRI_REST1_RL@rfMRI_REST2_LR@rfMRI_REST2_RL" + +randSeed=123 # random seed for PROFUMO + +OutputfMRIName="rfMRI_REST" +# set the MR concat fMRI name, if multi-run FIX was used, leave empty for single runs +ConcatName="" + +# set the output spectra size for individual projection, RunsXNumTimePoints #subjectExpectedTimepoints="3655" +subjectExpectedTimepoints="4800" + +# set temporal highpass full-width (2*sigma) used in preprocessing +HighPass="2000" + +#set fMRIResolution of data, like '2','1.60' or '2.40' +fMRIResolution="2.0" + +# PFM settings for REST data +# set the PFM dimensionality +PFMdim="76" + +PFMFolder=${StudyFolder}/$GroupAverageName/MNINonLinear/Results/${OutputfMRIName}_PFM_d${PFMdim} +# Reference image for PROFUMO +RefImage="${StudyFolder}/$GroupAverageName/MNINonLinear/Results/${OutputfMRIName}/${OutputfMRIName}_Atlas_MSMAll_hp${HighPass}_clean_rclean_tclean_meanvn.dscalar.nii" + +# set the file name component representing the preprocessing already done +fMRIProcSTRING="hp${HighPass}_clean_rclean_tclean" + +# set the mesh resolution, like '32' for 32k_fs_LR +LowResMesh="32" + +# Define OutputSTRING with seed designation +OutputSTRING="${OutputfMRIName}_d${PFMdim}_${GroupAverageName}_seed${randSeed}_PFMs" + +# RSN regression settings +FixLegacyBiasString="NO" +ScaleFactor="0.01" + +# Volume template file +VolumeTemplateCIFTI="${HOME}/data/HCPpipelines_ExampleData/${GroupAverageName}/MNINonLinear/${GroupAverageName}_CIFTIVolumeTemplate_${OutputfMRIName}.${fMRIResolution}.dscalar.nii" + +## PROFUMO settings +ProfumoConfig="${PFMFolder}/dataLocations.json" +TR="0.72" +ProfumoThreads="-1" # number of threads for PROFUMO, -1 means auto-detect physical cores +DOFCorrection="0.5" +CovModel="Subject" +nStarts="5" # number of multi-start iterations for PROFUMO +RandomSeed="$randSeed" # random seed for PROFUMO reproducibility +# RefImage will be auto-set based on data type below + +# build Profumo data location json +mkdir -p $PFMFolder +echo '{' > $ProfumoConfig +for Subject in $(echo $Subjlist | tr "@" "\n"); do + echo -e "\t\"$Subject\": {" >> $ProfumoConfig + for fMRIName in $(echo $fMRINames | tr "@" "\n"); do + runFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" + if [[ -e $runFile ]]; then + echo -e "\t\t\"$fMRIName\": \"$runFile\"," >> $ProfumoConfig + fi + done + perl -pi -e 'if (eof) { s/,$// }' $ProfumoConfig # remove trailing comma + echo -e "\t}," >> $ProfumoConfig +done +perl -pi -e 'if (eof) { s/,$// }' $ProfumoConfig # remove trailing comma +echo "}" >> $ProfumoConfig + +# PFM pipeline execution +echo "Starting PFM postprocessing pipeline" +echo "Data type: ${OutputfMRIName}" +echo "PFM dimension: ${PFMdim}" + +"${queuing_command[@]}" "$HCPPIPEDIR"/PFM/PFMPipeline.sh \ + --study-folder="$StudyFolder" \ + --subject-list="$Subjlist" \ + --fmri-names="$fMRINames" \ + --output-fmri-name="$OutputfMRIName" \ + --output-string="$OutputSTRING" \ + --proc-string="$fMRIProcSTRING" \ + --group-average-name="$GroupAverageName" \ + --pfm-dimension="$PFMdim" \ + --pfm-folder="$PFMFolder" \ + --surf-reg-name="$RegName" \ + --concat-name="$ConcatName" \ + --low-res-mesh="$LowResMesh" \ + --runs-timepoints="$subjectExpectedTimepoints" \ + --fix-legacy-bias="$FixLegacyBiasString" \ + --num-wishart="$NumWishart"\ + --scale-factor="$ScaleFactor" \ + --starting-step="$StartStep" \ + --stop-after-step="$StopStep" \ + --parallel-limit="$parLimit" \ + --matlab-run-mode="$MatlabMode" \ + --profumo-config="$ProfumoConfig" \ + --profumo-singularity="$ProfumoSingularity" \ + --profumo-tr="$TR" \ + --keep-wishart-files="$KeepWishartFiles" \ + --profumo-threads="$ProfumoThreads" \ + --profumo-dof-correction="$DOFCorrection" \ + --profumo-cov-model="$CovModel" \ + --profumo-multi-start-iterations="$nStarts" \ + --profumo-random-seed="$RandomSeed" \ + --ref-image="$RefImage" \ + --volume-template-file="$VolumeTemplateCIFTI" + +echo "PFM pipeline submitted successfully!" + diff --git a/PFM/.gitignore b/PFM/.gitignore new file mode 100644 index 000000000..6e91d7ef0 --- /dev/null +++ b/PFM/.gitignore @@ -0,0 +1 @@ +*.sif diff --git a/PFM/PFMPipeline.sh b/PFM/PFMPipeline.sh new file mode 100755 index 000000000..4c4700ccf --- /dev/null +++ b/PFM/PFMPipeline.sh @@ -0,0 +1,516 @@ +#!/bin/bash +set -eu + +pipedirguessed=0 +if [[ "${HCPPIPEDIR:-}" == "" ]] +then + pipedirguessed=1 + #fix this if the script is more than one level below HCPPIPEDIR + export HCPPIPEDIR="$(dirname -- "$0")/.." +fi + +source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/parallel.shlib" "$@" + +g_matlab_default_mode=1 + +# add steps to this array and in the switch cases below +pipelineSteps=(RunPROFUMO PostPROFUMO RSNRegression GroupPFMs) +defaultStart="${pipelineSteps[0]}" +defaultStopAfter="${pipelineSteps[${#pipelineSteps[@]} - 1]}" +stepsText="$(IFS=$'\n'; echo "${pipelineSteps[*]}")" + +#description to use in usage +opts_SetScriptDescription "implements complete PFM pipeline with four main steps: Run PROFUMO, Post-PROFUMO, RSN Regression, and Group PFM processing" + +#mandatory parameters +opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder that contains all subjects" +opts_AddMandatory '--subject-list' 'SubjlistRaw' '100206@100307...' "list of subject IDs separated by @s" +opts_AddMandatory '--fmri-names' 'fMRINames' 'rfMRI_REST1_LR@rfMRI_REST1_RL...' "list of fmri run names separated by @s" +opts_AddMandatory '--output-fmri-name' 'OutputfMRIName' 'rfMRI_REST' "name to use for PFM pipeline outputs" +opts_AddMandatory '--output-string' 'OutputSTRING' 'string' "output string for individual subject files (typically includes dimension, group name, and seed)" +opts_AddMandatory '--proc-string' 'fMRIProcSTRING' 'string' "file name component representing the preprocessing already done, e.g. '_Atlas_MSMAll_hp0_clean_tclean'" +opts_AddMandatory '--group-average-name' 'GroupAverageName' 'string' 'name to use for the group output folder' +opts_AddMandatory '--pfm-dimension' 'PFMdim' 'integer' "PFM dimensionality (e.g., 76, 92, 65)" +opts_AddMandatory '--pfm-folder' 'PFMFolder' 'path' "path to PFM results folder containing Results.ppp" +opts_AddMandatory '--surf-reg-name' 'RegName' 'MSMAll' "the registration string corresponding to the input files" +opts_AddMandatory '--profumo-config' 'ProfumoConfig' 'path' "path to PROFUMO JSON configuration file" +opts_AddMandatory '--profumo-tr' 'TR' "seconds" "repetition time for PROFUMO analysis" +opts_AddMandatory '--ref-image' 'RefImage' 'path' "reference image for PROFUMO postprocessing" +opts_AddMandatory '--runs-timepoints' 'RunsXNumTimePoints' "total timepoints across runs" "total timepoints across runs" +opts_AddMandatory '--concat-name' 'ConcatName' "concatenated fMRI name if using multi-run data" '' +opts_AddMandatory '--volume-template-file' 'VolumeTemplateFile' "volume template file path" '' + +#PROFUMO specific parameters +opts_AddOptional '--profumo-threads' 'ProfumoThreads' 'integer' "number of threads for PROFUMO" '-1' +opts_AddOptional '--profumo-dof-correction' 'DOFCorrection' 'float' "DOF correction for PROFUMO" '0.5' +opts_AddOptional '--profumo-cov-model' 'CovModel' 'string' "covariance model for PROFUMO" 'Subject' +opts_AddOptional '--profumo-singularity' 'ProfumoSingularity' 'path' "path to PROFUMO singularity container" +opts_AddOptional '--profumo-random-seed' 'RandomSeed' 'integer' "random seed for PROFUMO" '123' +opts_AddOptional '--profumo-multi-start-iterations' 'MultiStartIterations' 'integer' "number of iterations of group-level spatial decomposition before inferring full model" '5' +opts_AddOptional '--profumo-initial-maps' 'InitialMaps' 'path' "file to initialise the decomposition based on spatial maps" +opts_AddOptional '--profumo-load-sequentially' 'LoadSequentially' 'YES or NO' "load data sequentially in PROFUMO (useful for memory management)" 'YES' +opts_AddOptional '--num-wishart' 'NumWishart' 'integer' "number of Wishart filter iterations for prefiltering (0 to skip)" '0' + +# Post-Wishart filter specific parameters (only used if --num-wishart > 0) +opts_AddOptional '--keep-wishart-files' 'KeepWishartFiles' 'YES or NO' "keep Wishart-filtered files after PROFUMO instead of deleting (default NO)" 'NO' +opts_AddOptional '--variance-normalization' 'VarNorm' 'YES or NO' "Variance normalize data before PROFUMO (default YES)" 'YES' +opts_AddOptional '--weight-vertex-areas' 'VAweight' 'YES or NO' "Weight data by vertex areas before PROFUMO (default YES)" 'YES' + +#optional parameters +opts_AddOptional '--low-res-mesh' 'LowResMesh' 'string' "mesh resolution, like '32' for 32k_fs_LR" '32' + +#RSN regression specific parameters +opts_AddOptional '--fix-legacy-bias' 'FixLegacyBias' 'YES or NO' 'whether the input data used legacy bias correction' 'NO' +opts_AddOptional '--scale-factor' 'ScaleFactor' 'float' 'scale factor for RSN regression' '0.01' + + +#general settings +opts_AddOptional '--starting-step' 'startStep' 'step' "what step to start processing at, one of: +$stepsText" "$defaultStart" +opts_AddOptional '--stop-after-step' 'stopAfterStep' 'step' "what step to stop processing after, same valid values as --starting-step" "$defaultStopAfter" +opts_AddOptional '--parallel-limit' 'parLimit' 'integer' "set how many subjects to do in parallel during RSN regression, defaults to all detected physical cores" '-1' +opts_AddOptional '--matlab-run-mode' 'MatlabMode' '0, 1, or 2' "defaults to $g_matlab_default_mode +0 = compiled MATLAB +1 = interpreted MATLAB +2 = Octave" "$g_matlab_default_mode" + +opts_ParseArguments "$@" + +if ((pipedirguessed)) +then + log_Err_Abort "HCPPIPEDIR is not set, you must first source your edited copy of Examples/Scripts/SetUpHCPPipeline.sh" +fi + +#display the parsed/default values +opts_ShowValues + +if [[ "$ProfumoThreads" == "-1" ]]; then + ProfumoThreads=$(par_numphys) +fi + +#processing code goes here +IFS='@' read -a Subjlist <<<"$SubjlistRaw" +IFS='@' read -a fMRINamesArray <<<"$fMRINames" + +FixLegacyBiasBool=$(opts_StringToBool "$FixLegacyBias") +KeepWishartBool=$(opts_StringToBool "$KeepWishartFiles") +VarNormBool=$(opts_StringToBool "$VarNorm") +VAweightBool=$(opts_StringToBool "$VAweight") + +if ! [[ "$parLimit" == "-1" || "$parLimit" =~ [1-9][0-9]* ]] +then + log_Err_Abort "--parallel-limit must be a positive integer or -1, provided value: '$parLimit'" +fi + +function stepNameToInd() +{ + for ((i = 0; i < ${#pipelineSteps[@]}; ++i)) + do + if [[ "$1" == "${pipelineSteps[i]}" ]] + then + echo "$i" + return + fi + done + log_Err_Abort "unrecognized step name: '$1'" +} + + + +startInd=$(stepNameToInd "$startStep") +stopAfterInd=$(stepNameToInd "$stopAfterStep") + +if ((startInd > stopAfterInd)) +then + log_Err_Abort "starting step '$startStep' must not be after the stopping step '$stopAfterStep'" +fi + +RegString="" +if [[ "$RegName" != "" ]] +then + RegString="_$RegName" +fi + + +for ((stepInd = startInd; stepInd <= stopAfterInd; ++stepInd)) +do + stepName="${pipelineSteps[stepInd]}" + case "$stepName" in + (RunPROFUMO) + log_Msg "Running PROFUMO analysis step" + + # Validate required PROFUMO parameters + if [[ "$ProfumoConfig" == "" ]] + then + log_Err_Abort "PROFUMO config file must be specified with --profumo-config" + fi + if [[ "$ProfumoSingularity" == "" ]] + then + log_Err_Abort "PROFUMO singularity container must be specified with --profumo-singularity" + fi + if [[ "$RefImage" == "" ]] + then + log_Err_Abort "Reference image must be specified with --ref-image" + fi + + ProfumoConfigToUse="${ProfumoConfig}" + if [[ "$NumWishart" -gt 0 ]] + then + WFDir="${PFMFolder}/WishartFilter_WF${NumWishart}" + # Check if WF files already exist + wfComplete=true + for Subject in "${Subjlist[@]}" + do + for fMRIName in "${fMRINamesArray[@]}" + do + inputFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" + wfFile="${WFDir}/${Subject}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + if [[ -f "$inputFile" ]] && [[ ! -f "$wfFile" ]] + then + wfComplete=false + break 2 + fi + done + done + + if $wfComplete && [[ $KeepWishartBool == 1 ]]; then + log_Msg "WF files already exist in ${WFDir}" + else + log_Msg "Running Wishart filtering with ${NumWishart} iterations" + for Subject in "${Subjlist[@]}" + do + mkdir -p "${WFDir}/${Subject}" + + if [[ "$ConcatName" != "" ]] # multi_run data + then + # Use already concatenated file + concatFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${ConcatName}/${ConcatName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" + clean_VN="${StudyFolder}/${Subject}/MNINonLinear/Results/${ConcatName}/${ConcatName}_Atlas${RegString}_${fMRIProcSTRING}_vn.dscalar.nii" + concatOutFile="${WFDir}/${Subject}/${ConcatName}_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + if [[ -f "$concatFile" ]] + then + log_Msg "Applying Wishart filter to concat file for subject $Subject" + "$HCPPIPEDIR"/PFM/scripts/ApplyWFProfumo.sh \ + --input="$concatFile" \ + --output="$concatOutFile" \ + --num-wishart="$NumWishart" \ + --matlab-run-mode="$MatlabMode" + + if [[ "$VAweightBool" == 1 ]]; then + # create temporary VA_norm cifti with volume grayordinates filled with ones areas for weighting + VAnorm=${StudyFolder}/${Subject}/T1w/fsaverage_LR${LowResMesh}k/${Subject}.midthickness${RegString}_va_norm.${LowResMesh}k_fs_LR.dscalar.nii + tempfiles_create "tmp_VAgray_XXXXXX.dscalar.nii" tmp_VAgray_file + tempfiles_create "tmp_jnk_XXXXXX.nii.gz" tmp_jnk_file + tempfiles_create "tmp_roi_XXXXXX.nii.gz" tmp_roi_file + wb_command -cifti-separate "${concatOutFile}" COLUMN -volume-all "$tmp_jnk_file" -roi "$tmp_roi_file" -crop + wb_command -cifti-create-dense-from-template "${concatOutFile}" "$tmp_VAgray_file" -cifti "$VAnorm" -volume-all "$tmp_roi_file" -from-cropped + fi + + # Split back into individual runs and restore means + cumTP=0 + for fMRIName in "${fMRINamesArray[@]}" + do + origFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" + if [[ -f "$origFile" ]] + then + nTP=$(wb_command -file-information "$origFile" -only-number-of-maps) + startIdx=$((cumTP + 1)) + endIdx=$((cumTP + nTP)) + outFile="${WFDir}/${Subject}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + wb_command -cifti-merge "$outFile" -direction ROW -cifti "$concatOutFile" -index "$startIdx" -up-to "$endIdx" # naive splitting + + ## The concatenated timeseries are intensity normalized and differences in unstructured noise variance between runs and the means have been removed. + # For model-free analyses (i.e., not task-GLM) that prefer single runs, it is best to simply deconcatenate the runs. + # If variance normalization is desired, use the same _clean_vn file from the concatenated folder for each run, rather than the original _vn files, + # which may cause extreme values in areas of little or no signal and require more complex handling. + if [[ "$VarNormBool" == 1 ]];then + log_Msg "Normalizing variance" + wb_command -cifti-math "(TCS / clean_VN)" ${outFile} \ + -var TCS ${outFile} \ + -var clean_VN ${clean_VN} -select 1 1 -repeat + fi + + if [[ "$VAweightBool" == 1 ]];then + log_Msg "Weighting data by average vertex areas" + wb_command -cifti-math "(TCS * VA)" ${outFile} \ + -var TCS ${outFile} \ + -var VA ${tmp_VAgray_file} -select 1 1 -repeat + fi + + cumTP=$endIdx + fi + done + fi + else # single run data + echo ToDO + # No concat file not supplied so create a temporary one for Wishart filtering + # demeanVNarray=() + # vnScalarArray=() + # for fMRIName in "${fMRINamesArray[@]}" + # do + # inputFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" + # vnScalarFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_vn.dscalar.nii" + # meanFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas_mean.dscalar.nii" + # outputFile="${WFDir}/${Subject}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + + # # demean and variance normalize runs + # wb_command -cifti-math "(TCS - MEAN) / VN" "$outputFile" -var TCS "$inputFile" -var MEAN "$meanFile" -var VN "$vnScalarFile" -select 1 1 -repeat + # demeanVNarray+=("$outputFile") + # vnScalarArray+=("$vnScalarFile") + # done + + # # concatenate the demeaned+VN files + # concatOutFile="${WFDir}/${Subject}/CONCAT_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + # wb_shortcuts -cifti-concatenate "${concatOutFile}" "${demeanVNarray[*]}" + + + # log_Msg "Applying Wishart filter for subject $Subject" + # "$HCPPIPEDIR"/PFM/scripts/ApplyWFProfumo.sh \ + # --input="$concatOutFile" \ + # --output="$concatOutFile" \ + # --num-wishart="$NumWishart" \ + # --matlab-run-mode="$MatlabMode" + + # # deconcatenate the Wishart filtered data back into individual runs + # # (each run has its own VN file, so un-VN with each separately) + # cumTP=0 + # for fMRIName in "${fMRINamesArray[@]}" + # do + # origFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" + # vnScalarFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_vn.dscalar.nii" + # meanFile="${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas_mean.dscalar.nii" + # if [[ -f "$origFile" ]] + # then + # nTP=$(wb_command -file-information "$origFile" -only-number-of-maps) + # startIdx=$((cumTP + 1)) + # endIdx=$((cumTP + nTP)) + # outFile="${WFDir}/${Subject}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + # wb_command -cifti-merge "$outFile" -direction ROW -cifti "$concatOutFile" -index "$startIdx" -up-to "$endIdx" + + # # un-variance normalize and un-demean each post-WF run + # wb_command -cifti-math "(TCS / VN) + MEAN" "$outFile" -var TCS "$outFile" -var MEAN "$meanFile" -var VN "$vnScalarFile" -select 1 1 -repeat + + # cumTP=$endIdx + # fi + # done + fi + done + fi + + # Build JSON pointing at WF files + ProfumoConfigToUse="${WFDir}/wishart_dataLocations.json" + echo '{' > "$ProfumoConfigToUse" + for Subject in "${Subjlist[@]}" + do + echo -e "\t\"$Subject\": {" >> "$ProfumoConfigToUse" + for fMRIName in "${fMRINamesArray[@]}" + do + WFFile="${WFDir}/${Subject}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}_WF.dtseries.nii" + if [[ -f "$WFFile" ]] + then + echo -e "\t\t\"$fMRIName\": \"$WFFile\"," >> "$ProfumoConfigToUse" + fi + done + perl -pi -e 'if (eof) { s/,$// }' "$ProfumoConfigToUse" + echo -e "\t}," >> "$ProfumoConfigToUse" + done + perl -pi -e 'if (eof) { s/,$// }' "$ProfumoConfigToUse" + echo "}" >> "$ProfumoConfigToUse" + log_Msg "WF complete" + fi + + + # Set up PROFUMO paths + PFM_PATH="${PFMFolder}/Analysis.pfm" + RESULTS_PATH="${PFMFolder}/Results.ppp" + REAL_REF_IMAGE=$(readlink -f "${RefImage}") + + # Calculate low rank data parameter + LowRankData=$((PFMdim * 5)) + + # if PFM output directory exists, clear it (except dataLocations.json) because PROFUMO otherwise creates "+" files instead of overwriting + if [[ -d "${PFMFolder}" ]] + then + log_Warn "PFM output folder ${PFMFolder} already exists, clearing contents" + find "${PFMFolder}" -mindepth 1 -not -name "dataLocations.json" -not -name ".*" -not -path "*/WishartFilter_WF*" -delete 2>/dev/null || true + # ignore errors due to nfs silly renamed files, or similar + fi + + # Build optional initialMaps argument + InitialMapsArg="" + if [[ -n "${InitialMaps}" && -f "${InitialMaps}" ]] + then + InitialMapsArg="--initialMaps ${InitialMaps}" + fi + + # Build optional loadSequentially argument + LoadSequentiallyArg="" + LoadSequentiallyBool=$(opts_StringToBool "$LoadSequentially") + if ((LoadSequentiallyBool)) + then + LoadSequentiallyArg="--loadSequentially" + fi + + # files were written with an older version of cifti-matlab with 8-byte instead of 16-byte alignment. + if [[ "${NumWishart}" -eq 0 ]] + then + cat "${ProfumoConfig}" | \ + while IFS= read -r line; do + if [[ "$line" != *'.nii"'* ]]; then continue;fi # Only process lines that contain .nii" + filePath=$(echo "$line" | sed -E 's/^[[:space:]]*"[^"]*"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/') + wb_command -file-convert -cifti-version-convert "$filePath" 2 "$filePath" + done + fi + + # log_Msg "Running PROFUMO decomposition with dimension ${PFMdim}" + cmd=(apptainer exec --bind $(dirname "${StudyFolder}") \ + --env PROFUMODIR=/opt/profumo \ + --env PYTHONNOUSERSITE=1 \ + "${ProfumoSingularity}" \ + /opt/profumo/C++/PROFUMO "${ProfumoConfigToUse}" \ + "${PFMdim}" "${PFM_PATH}" \ + --useHRF "${TR}" --covModel "${CovModel}" --dofCorrection "${DOFCorrection}" \ + --nThreads "${ProfumoThreads}" --lowRankData "${LowRankData}" --randomSeed "${RandomSeed}" \ + --multiStartIterations "${MultiStartIterations}" ${LoadSequentiallyArg} ${InitialMapsArg}) + log_Msg "running command: ${cmd[*]}" + "${cmd[@]}" + + #Cleanup WF files + if [[ "$NumWishart" -gt 0 ]] + then + if ((KeepWishartBool)) + then + log_Msg "Keeping Wishart filtered files in ${WFDir}" + else + log_Msg "Cleaning up Wishart filtered files" + rm -rf "${WFDir}" 2>/dev/null || true # ignore errors due to nfs silly renamed files, or similar + fi + fi + ;; + + (PostPROFUMO) + log_Msg "Running PROFUMO postprocessing" + PFM_PATH="${PFMFolder}/Analysis.pfm" + RESULTS_PATH="${PFMFolder}/Results.ppp" + REAL_REF_IMAGE=$(readlink -f "${RefImage}") + + # Remove any existing Results.ppp directory + # so postprocess_results.py writes fresh output to Results.ppp + if [[ -d "${PFMFolder}/Results.ppp" ]] + then + log_Warn "Results.ppp folder ${PFMFolder}/Results.ppp already exists, clearing before postprocessing" + rm -rf "${PFMFolder}"/Results.ppp 2>/dev/null || true # ignore errors due to nfs silly renamed files, or similar + fi + + cmd=(apptainer exec --bind $(dirname "${StudyFolder}") \ + --env PROFUMODIR=/opt/profumo \ + --env PYTHONNOUSERSITE=1 \ + "${ProfumoSingularity}" \ + /opt/fsl/fslpython/envs/profumo/bin/python3 /opt/profumo/Python/postprocess_results.py \ + --web-report \ + "${PFM_PATH}" \ + "${RESULTS_PATH}" \ + "${REAL_REF_IMAGE}") + log_Msg "Running command: ${cmd[*]}" + "${cmd[@]}" + + log_Msg "Running PostPROFUMO step" + "$HCPPIPEDIR"/PFM/scripts/PostPROFUMO.sh \ + --study-folder="$StudyFolder" \ + --subject-list="$SubjlistRaw" \ + --fmri-names="$fMRINames" \ + --concat-name="$ConcatName" \ + --proc-string="_Atlas${RegString}_${fMRIProcSTRING}" \ + --output-fmri-name="$OutputfMRIName" \ + --output-string="$OutputSTRING" \ + --surf-reg-name="$RegName" \ + --low-res-mesh="$LowResMesh" \ + --profumo-tr="$TR" \ + --pfm-folder="$PFMFolder" \ + --variance-normalize="$VarNorm" \ + --weight-vertex-areas="$VAweight" \ + --matlab-run-mode="$MatlabMode" + + ;; + (RSNRegression) + log_Msg "Running RSNRegression step" + + # Set up template paths + for Subject in "${Subjlist[@]}" + do + if [[ "$ConcatName" != "" ]] + then + fMRINamesForSub="${ConcatName}" + else + # Build list of existing fMRI files for this subject (same logic as your example) + fMRINamesForSub="" + for fMRIName in "${fMRINamesArray[@]}" + do + if [[ -f "${StudyFolder}/${Subject}/MNINonLinear/Results/${fMRIName}/${fMRIName}_Atlas${RegString}_${fMRIProcSTRING}.dtseries.nii" ]] + then + if [[ "$fMRINamesForSub" != "" ]] + then + fMRINamesForSub="${fMRINamesForSub}@${fMRIName}" + else + fMRINamesForSub="${fMRIName}" + fi + fi + done + fi + + if [[ "$fMRINamesForSub" == "" ]] + then + log_Warn "No valid fMRI runs found for subject $Subject, skipping" + continue + fi + + # Set maps for dual regression + GroupMaps="${PFMFolder}/Results.ppp/Maps/Group.dscalar.nii" + + # Build RSN regression command + rsn_cmd=("$HCPPIPEDIR"/global/scripts/RSNregression.sh + --study-folder="$StudyFolder" + --subject="$Subject" + --subject-timeseries="$fMRINamesForSub" # "$fMRINamesForSub" + --surf-reg-name="$RegName" + --low-res="$LowResMesh" + --proc-string="_$fMRIProcSTRING" + --method="dual" + --output-string="$OutputSTRING" + --output-spectra="$RunsXNumTimePoints" + --volume-template-cifti="$VolumeTemplateFile" + --output-z=1 + --fix-legacy-bias="$FixLegacyBias" + --scale-factor="$ScaleFactor" + --group-maps="$GroupMaps" + ) + + # Queue parallel job + par_addjob "${rsn_cmd[@]}" + done + + # Run the jobs + par_runjobs "$parLimit" + ;; + (GroupPFMs) + log_Msg "Running GroupPFMs step" + "$HCPPIPEDIR"/PFM/scripts/GroupPFMs.sh \ + --study-folder="$StudyFolder" \ + --subject-list="$SubjlistRaw" \ + --pfm-dimension="$PFMdim" \ + --output-string="$OutputSTRING" \ + --surf-reg-name="$RegName" \ + --low-res-mesh="$LowResMesh" \ + --runs-timepoints="$RunsXNumTimePoints" \ + --pfm-folder="$PFMFolder" \ + --matlab-run-mode="$MatlabMode" + ;; + (*) #NOTE: this case MUST be last + log_Err_Abort "internal error: unimplemented pipeline step '$stepName'" + ;; + esac + log_Msg "step $stepName complete" +done diff --git a/PFM/scripts/ApplyWFProfumo.m b/PFM/scripts/ApplyWFProfumo.m new file mode 100644 index 000000000..30a3b4028 --- /dev/null +++ b/PFM/scripts/ApplyWFProfumo.m @@ -0,0 +1,7 @@ +function ApplyWFProfumo(inputFile, outputFile, numWisharts) + numWisharts = str2double(numWisharts); + cii = ciftiopen(strtrim(inputFile), 'wb_command'); + Out = icaDim(cii.cdata, 0, 1, -1, numWisharts); + cii.cdata = Out.data; + ciftisave(cii, strtrim(outputFile), 'wb_command'); +end \ No newline at end of file diff --git a/PFM/scripts/ApplyWFProfumo.sh b/PFM/scripts/ApplyWFProfumo.sh new file mode 100755 index 000000000..8b860f221 --- /dev/null +++ b/PFM/scripts/ApplyWFProfumo.sh @@ -0,0 +1,84 @@ +#!/bin/bash +set -eu + +pipedirguessed=0 +if [[ "${HCPPIPEDIR:-}" == "" ]] +then + pipedirguessed=1 + export HCPPIPEDIR="$(dirname -- "$0")/../.." +fi + +source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" +g_matlab_default_mode=1 + +opts_SetScriptDescription "applies Wishart filter to CIFTI dtseries files for PROFUMO" + +opts_AddMandatory '--input' 'inputFile' 'file' "comma-separated list of input dtseries files" +opts_AddMandatory '--output' 'outputFile' 'file' "comma-separated list of output wishart-filtered dtseries files" +opts_AddMandatory '--num-wishart' 'numWisharts' 'integer' "number of Wishart distributions to fit" +opts_AddOptional '--matlab-run-mode' 'MatlabMode' '0, 1, or 2' "defaults to $g_matlab_default_mode + +0 = compiled MATLAB +1 = interpreted MATLAB +2 = Octave" "$g_matlab_default_mode" + +opts_ParseArguments "$@" + +if ((pipedirguessed)) +then + log_Err_Abort "HCPPIPEDIR is not set, you must first source your edited copy of Examples/Scripts/SetUpHCPPipeline.sh" +fi + +opts_ShowValues + +case "$MatlabMode" in + (0) + if [[ "${MATLAB_COMPILER_RUNTIME:-}" == "" ]] + then + log_Err_Abort "to use compiled matlab, you must set and export the variable MATLAB_COMPILER_RUNTIME" + fi + ;; + (1) + matlab_interpreter=(matlab -nodisplay -nosplash) + ;; + (2) + matlab_interpreter=(octave-cli -q --no-window-system) + ;; + (*) + log_Err_Abort "unrecognized matlab mode '$MatlabMode', use 0, 1, or 2" + ;; +esac + +this_script_dir=$(dirname "$0") + +matlab_argarray=("$inputFile" "$outputFile" "$numWisharts") + +case "$MatlabMode" in + (0) + matlab_cmd=("$this_script_dir/Compiled_WishartFilter/run_WishartFilter.sh" "$MATLAB_COMPILER_RUNTIME" "${matlab_argarray[@]}") + log_Msg "running compiled matlab command: ${matlab_cmd[*]}" + "${matlab_cmd[@]}" + ;; + (1 | 2) + matlab_args="" + for thisarg in "${matlab_argarray[@]}" + do + if [[ "$matlab_args" != "" ]] + then + matlab_args+=", " + fi + matlab_args+="'$thisarg'" + done + matlabcode=" + addpath('$HCPPIPEDIR/global/matlab/icaDim'); + addpath('$HCPPIPEDIR/global/matlab'); + addpath('$this_script_dir'); + addpath('$HCPCIFTIRWDIR'); + ApplyWFProfumo($matlab_args);" + + log_Msg "running matlab code: $matlabcode" + "${matlab_interpreter[@]}" <<<"$matlabcode" + echo + ;; +esac \ No newline at end of file diff --git a/PFM/scripts/GroupPFMs.m b/PFM/scripts/GroupPFMs.m new file mode 100755 index 000000000..5f1950188 --- /dev/null +++ b/PFM/scripts/GroupPFMs.m @@ -0,0 +1,126 @@ +function GroupPFMs(StudyFolder, SubjlistRaw, PFMdim, OutputSTRING, RegName, LowResMesh, RunsXNumTimePoints, PFMFolder) +% GroupPFMs(StudyFolder, SubjlistRaw, PFMdim, OutputSTRING, RegName, LowResMesh, RunsXNumTimePoints, PFMFolder) +% This function aggregates individual subject PFM results and computes +% group-level time course masks, spectra, maps, and statistics. +% +% Inputs: +% StudyFolder - Path to the study directory +% SubjlistRaw - Subject list as @ separated string +% PFMdim - PFM dimensionality +% OutputSTRING - Output string for files +% RegName - Registration string (e.g., '_MSMAll') +% LowResMesh - Mesh resolution (e.g., '32' for 32k_fs_LR) +% RunsXNumTimePoints - Total expected timepoints across runs +% PFMFolder - Output folder for group-level results + +%% Initialize parameters +wbcommand = 'wb_command'; + +%% Parse input arguments +subjList = regexp(SubjlistRaw,'@','split'); +nS = numel(subjList); +RunsXNumTimePoints = str2double(RunsXNumTimePoints); +PFMdim = str2double(PFMdim); +if nargin < 8; error('All arguments are required.'); end % Validate all inputs + +%% Preallocate arrays for group concatenation +% TCSMask: binary mask indicating valid timepoints per subject +% TCSAll: concatenated time courses across subjects +% spectra, PFMmaps, PFMvolMaps: accumulators for group averages +[TCSMask, TCSAll] = deal(zeros(PFMdim, RunsXNumTimePoints, nS, 'single')); +[spectra, PFMmaps, PFMvolMaps] = deal([]); + +%% Load and accumulate individual subject results +for iS = 1:nS + subj = subjList{iS}; + subjDir = [StudyFolder '/' subj '/MNINonLinear/fsaverage_LR' LowResMesh 'k']; + fprintf('Processing %s ... \n', subj); + + %% Load individual PFM results from standard subject locations + % Load spatial maps, volume maps, time courses, and power spectra + PFMMapsSub = ciftiopen([subjDir '/' subj '.' OutputSTRING '_DR' RegName '.' LowResMesh 'k_fs_LR.dscalar.nii'], wbcommand); + PFMVolMapsSub = ciftiopen([subjDir '/' subj '.' OutputSTRING '_DR' RegName '_vol.' LowResMesh 'k_fs_LR.dscalar.nii'], wbcommand); + TCSSub = ciftiopen([subjDir '/' subj '.' OutputSTRING '_DR' RegName '_ts.' LowResMesh 'k_fs_LR.sdseries.nii'], wbcommand); + SpectraSub = ciftiopen([subjDir '/' subj '.' OutputSTRING '_DR' RegName '_spectra.' LowResMesh 'k_fs_LR.sdseries.nii'], wbcommand); + + %% Clean up NaNs and Infs in volume maps + % Replace invalid values with zeros to prevent propagation to group statistics + infMask = isinf(PFMVolMapsSub.cdata); + nanMask = isnan(PFMVolMapsSub.cdata); + if any(infMask, 'all') + warning('Found Infs in PFM VolMaps for subject %s. Replacing with zeros.\n', subj); + PFMVolMapsSub.cdata(isinf(PFMVolMapsSub.cdata)) = 0; + end + if any(nanMask, 'all') + warning('Found NaNs in PFM VolMaps for subject %s. Replacing with zeros.\n', subj); + PFMVolMapsSub.cdata(isnan(PFMVolMapsSub.cdata)) = 0; + end + + %% Store subject time course in concatenated array + TCSAll(1:size(TCSSub.cdata, 1), 1:size(TCSSub.cdata, 2), iS) = TCSSub.cdata; + + %% Accumulate spectra and maps for group averaging + % Only accumulate if subject has expected number of timepoints + if size(TCSSub.cdata, 2) == RunsXNumTimePoints + TCSMask(:, :, iS) = repmat(1, PFMdim, RunsXNumTimePoints, 1); + if isempty(spectra) + spectra = SpectraSub; + spectra.cdata = SpectraSub.cdata * 0; + end + spectra.cdata = spectra.cdata + SpectraSub.cdata; + end + + % Accumulate spatial maps from all subjects with valid data + if isempty(PFMmaps) + PFMmaps = PFMMapsSub; + PFMmaps.cdata = PFMMapsSub.cdata * 0; + PFMvolMaps = PFMVolMapsSub; + PFMvolMaps.cdata = PFMVolMapsSub.cdata * 0; + end + PFMmaps.cdata = PFMmaps.cdata + PFMMapsSub.cdata; + PFMvolMaps.cdata = PFMvolMaps.cdata + PFMVolMapsSub.cdata; +end % for iS = 1:nS + +%% Create output directory if needed +if ~exist(PFMFolder, 'dir'); mkdir(PFMFolder); end +dimStr = num2str(PFMdim); + +%% Concatenate and reshape group time courses +% Create single concatenated time series from all subjects +TCSMaskConcat = TCSSub; +TCSMaskConcat.cdata = squeeze(reshape(TCSMask, PFMdim, RunsXNumTimePoints * nS)); +TCSFullConcat = TCSSub; +TCSFullConcat.cdata = squeeze(reshape(TCSAll, PFMdim, RunsXNumTimePoints * nS)); +ciftisavereset(TCSMaskConcat, [PFMFolder '/PFM_TCSMASK_' dimStr '.sdseries.nii'], wbcommand); +ciftisavereset(TCSFullConcat, [PFMFolder '/PFM_TCS_' dimStr '.sdseries.nii'], wbcommand); + +%% Compute group average time courses +% Calculate mean time course and mean absolute value time course +TCSAVG = TCSSub; +TCSAVG.cdata = sum(TCSAll .* TCSMask, 3) / nS; +TCSABSAVG = TCSSub; +TCSABSAVG.cdata = sum(abs(TCSAll .* TCSMask), 3) / nS; +ciftisavereset(TCSAVG, [PFMFolder '/PFM_AVGTCS_' dimStr '.sdseries.nii'], wbcommand); +ciftisavereset(TCSABSAVG, [PFMFolder '/PFM_ABSAVGTCS_' dimStr '.sdseries.nii'], wbcommand); + +%% Compute group-level statistics +% Calculate variance explained by each PFM component +PFMTSTDs = std(TCSFullConcat.cdata, [], 2); +PFMPercentVariances = (((PFMTSTDs .^ 2) / sum(PFMTSTDs .^ 2)) * 100); +dlmwrite([PFMFolder '/PFM_stats_' dimStr '.wb_annsub.csv'], [(1:PFMdim)' round(PFMPercentVariances, 2)], ','); + +%% Average group spectra +% Normalize by number of subjects with valid data +spectra.cdata = spectra.cdata / nS; +ciftisavereset(spectra, [PFMFolder '/PFM_Spectra_' dimStr '.sdseries.nii'], wbcommand); + +%% Average group spatial maps +% Compute mean PFM maps across all subjects +PFMmaps.cdata = PFMmaps.cdata / nS; +PFMvolMaps.cdata = PFMvolMaps.cdata / nS; + +%% Save group-level spatial maps +% Output group-averaged surface and volume PFM maps +ciftisavereset(PFMmaps, [PFMFolder '/PFM_Maps_' num2str(PFMdim) '.dscalar.nii'], wbcommand); +ciftisavereset(PFMvolMaps, [PFMFolder '/PFM_VolMaps_' num2str(PFMdim) '.dscalar.nii'], wbcommand); +end \ No newline at end of file diff --git a/PFM/scripts/GroupPFMs.sh b/PFM/scripts/GroupPFMs.sh new file mode 100755 index 000000000..fe0429de4 --- /dev/null +++ b/PFM/scripts/GroupPFMs.sh @@ -0,0 +1,99 @@ +#!/bin/bash +set -eu + +pipedirguessed=0 +if [[ "${HCPPIPEDIR:-}" == "" ]] +then + pipedirguessed=1 + export HCPPIPEDIR="$(dirname -- "$0")/../.." +fi + +source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" +g_matlab_default_mode=1 + +opts_SetScriptDescription "Aggregate individual subject PFM results and compute group-level time course masks, spectra, maps, and statistics" + +#arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] +opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder that contains all subjects" +opts_AddMandatory '--subject-list' 'SubjlistRaw' '100206@100307...' "list of subject IDs separated by @s" +opts_AddMandatory '--pfm-dimension' 'PFMdim' 'integer' "PFM dimensionality (e.g., 76, 92, 65)" +opts_AddMandatory '--output-string' 'OutputSTRING' 'string' "output string for files" +opts_AddMandatory '--surf-reg-name' 'RegName' 'MSMAll' "the registration string corresponding to the input files" +opts_AddMandatory '--low-res-mesh' 'LowResMesh' 'string' "mesh resolution" +opts_AddMandatory '--runs-timepoints' 'RunsXNumTimePoints' 'integer' "total timepoints across runs (e.g., 4800 for rest, 3880 for task)" +opts_AddMandatory '--pfm-folder' 'PFMFolder' 'path' "path to PFM results folder" +opts_AddOptional '--matlab-run-mode' 'MatlabMode' '0, 1, or 2' "defaults to $g_matlab_default_mode +0 = compiled MATLAB +1 = interpreted MATLAB +2 = Octave" "$g_matlab_default_mode" + +opts_ParseArguments "$@" + +if ((pipedirguessed)) +then + log_Err_Abort "HCPPIPEDIR is not set, you must first source your edited copy of Examples/Scripts/SetUpHCPPipeline.sh" +fi + +#display the parsed/default values +opts_ShowValues + +RegString="" +if [[ "$RegName" != "" ]] +then + RegString="_$RegName" +fi + +case "$MatlabMode" in + (0) + if [[ "${MATLAB_COMPILER_RUNTIME:-}" == "" ]] + then + log_Err_Abort "to use compiled matlab, you must set and export the variable MATLAB_COMPILER_RUNTIME" + fi + ;; + (1) + matlab_interpreter=(matlab -nodisplay -nosplash) + ;; + (2) + matlab_interpreter=(octave-cli -q --no-window-system) + ;; + (*) + log_Err_Abort "unrecognized matlab mode '$MatlabMode', use 0, 1, or 2" + ;; +esac + +#shortcut in case the folder gets renamed +this_script_dir=$(dirname "$0") + +#matlab function arguments converted to strings +matlab_argarray=("$StudyFolder" "$SubjlistRaw" "$PFMdim" "$OutputSTRING" "$RegString" "$LowResMesh" "$RunsXNumTimePoints" "$PFMFolder") + +case "$MatlabMode" in + (0) + matlab_cmd=("$this_script_dir/Compiled_GroupPFMs/run_GroupPFMs.sh" "$MATLAB_COMPILER_RUNTIME" "${matlab_argarray[@]}") + log_Msg "running compiled matlab command: ${matlab_cmd[*]}" + "${matlab_cmd[@]}" + ;; + (1 | 2) + #reformat argument array so matlab sees them as strings + matlab_args="" + for thisarg in "${matlab_argarray[@]}" + do + if [[ "$matlab_args" != "" ]] + then + matlab_args+=", " + fi + matlab_args+="'$thisarg'" + done + matlabcode=" + addpath('$HCPPIPEDIR/global/matlab'); + addpath('$this_script_dir'); + addpath('$HCPCIFTIRWDIR'); + GroupPFMs($matlab_args);" + + log_Msg "running matlab code: $matlabcode" + "${matlab_interpreter[@]}" <<<"$matlabcode" + echo + ;; +esac \ No newline at end of file diff --git a/PFM/scripts/PostPROFUMO.m b/PFM/scripts/PostPROFUMO.m new file mode 100755 index 000000000..346a34700 --- /dev/null +++ b/PFM/scripts/PostPROFUMO.m @@ -0,0 +1,149 @@ +function PostPROFUMO(StudyFolder, SubjListRaw, fMRIListRaw, ConcatName, fMRIProcSTRING, OutputfMRIName, OutputSTRING, RegString, LowResMesh, TR, PFMFolder,VarNormBool,VAweightBool) +% PostPROFUMO(StudyFolder, SubjListRaw, fMRIListRaw, ConcatName, fMRIProcSTRING, OutputfMRIName, OutputSTRING, RegString, LowResMesh, TR, PFMFolder) +% This function imports PROFUMO results and generates CIFTI-format time courses +% and power spectra for each subject. The outputs are used for subsequent +% group-level PFM analysis. +% +% Inputs: +% StudyFolder - Path to the study directory +% SubjListRaw - Subject list as @ separated string +% fMRIListRaw - fMRI run names as @ separated string +% ConcatName - Name of concatenated fMRI dataset (empty if single runs) +% fMRIProcSTRING - Processing string component (e.g., '_Atlas_hp200_clean') +% OutputfMRIName - Name of output fMRI dataset +% OutputSTRING - Output string for files +% RegString - Registration string +% LowResMesh - Mesh resolution (e.g., '10' for 10k) +% TR - Repetition time in seconds +% PFMFolder - Path to PROFUMO results folder +% VarNormBool - Boolean flag for variance normalization +% VAweightBool - Boolean flag for vertex area weighting + +%% Parse string inputs and initialize +Subjlist = strsplit(SubjListRaw, '@'); +fMRINames = strsplit(fMRIListRaw, '@'); +TR = str2double(TR); +VarNormBool = logical(str2double(VarNormBool)); +VAweightBool = logical(str2double(VAweightBool)); +wbcommand = 'wb_command'; + +%% Main loop: Process each subject +for s = 1:numel(Subjlist) + fprintf('Processing subject %d/%d: %s\n', s, numel(Subjlist), Subjlist{s}); + + %% Identify available fMRI runs for this subject + % Determine which fMRI runs exist for this subject + % If ConcatName is specified, use concatenated version; otherwise check individual runs + subfMRINames = {}; + if ~strcmp(ConcatName, '') + % Multi-run data: check if concatenated dataset exists + if exist([StudyFolder '/' Subjlist{s} '/MNINonLinear/Results/' ConcatName '/' ConcatName fMRIProcSTRING '.dtseries.nii'],'file') + c = 1; + for r = 1:numel(fMRINames) + if exist([StudyFolder '/' Subjlist{s} '/MNINonLinear/Results/' fMRINames{r} '/' fMRINames{r} fMRIProcSTRING '.dtseries.nii'],'file') + subfMRINames{c} = fMRINames{r}; + c = c + 1; + end + end % for r = 1:numel(fMRINames) + end + else + % Single-run data: check which runs exist + c = 1; + for r = 1:numel(fMRINames) + if exist([StudyFolder '/' Subjlist{s} '/MNINonLinear/Results/' fMRINames{r} '/' fMRINames{r} fMRIProcSTRING '.dtseries.nii'],'file') + subfMRINames{c} = fMRINames{r}; + c = c + 1; + end + end % for r = 1:numel(fMRINames) + end + + %% Process subject if valid runs found + if numel(subfMRINames) ~= 0 + + if VAweightBool + % create temporary VA_norm cifti with volume grayordinates filled with ones areas for weighting + ciftiTemplate = [StudyFolder '/' Subjlist{s} '/MNINonLinear/Results/' ConcatName '/' ConcatName RegString fMRIProcSTRING '_vn.dscalar.nii']; % use clean_VN as cifti template + VAnorm = [StudyFolder '/' Subjlist{s} '/T1w/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.midthickness' RegString '_va_norm.' LowResMesh 'k_fs_LR.dscalar.nii']; + tmp_VAgray_file = [tempname '.dscalar.nii']; + tmp_jnk_file = [tempname '.nii.gz']; + tmp_roi_file = [tempname '.nii.gz']; + system(sprintf('%s -cifti-separate "%s" COLUMN -volume-all "%s" -roi "%s" -crop', wbcommand, ciftiTemplate, tmp_jnk_file, tmp_roi_file)); + system(sprintf('%s -cifti-create-dense-from-template "%s" "%s" -cifti "%s" -volume-all "%s" -from-cropped', wbcommand, ciftiTemplate, tmp_VAgray_file, VAnorm, tmp_roi_file)); + end + + %% Load and concatenate PFM time courses and amplitudes + % Load PROFUMO outputs and amplitude-modulate time courses + origTCS = []; % Original unmodulated time courses + TCS = []; % Amplitude-modulated time courses + for r = 1:numel(subfMRINames) + runTCS = load([PFMFolder '/Results.ppp/TimeCourses/sub-' Subjlist{s} '_run-' subfMRINames{r} '.csv']); + runAmp = load([PFMFolder '/Results.ppp/Amplitudes/sub-' Subjlist{s} '_run-' subfMRINames{r} '.csv']); + + origTCS = [origTCS ; runTCS]; + TCS = [TCS ; runTCS .* repmat(runAmp', size(runTCS, 1), 1)]; + end % for r = 1:numel(subfMRINames) + + %% Create original time course and spectral CIFTI files + % Generate CIFTI structure for unmodulated time courses + PFMTCSorig = cifti_struct_create_sdseries(origTCS','step',TR); + + % Store power spectra + ts.Nnodes = size(origTCS, 2); + ts.Nsubjects = 1; + ts.ts = origTCS; + ts.NtimepointsPerSubject = size(origTCS, 1); + PFMSpectraorig = cifti_struct_create_sdseries(nets_spectra_sp(ts)','step',1/TR); + + %% Create time course and spectral CIFTI files + % Generate CIFTI structure for time courses + PFMTCS = cifti_struct_create_sdseries(TCS','step',TR); + + % Store power spectra + ts.Nnodes = size(TCS, 2); + ts.Nsubjects = 1; + ts.ts = TCS; + ts.NtimepointsPerSubject = size(TCS, 1); + PFMSpectra = cifti_struct_create_sdseries(nets_spectra_sp(ts)','step',1/TR); + + %% Save non-map results + % Save original and amplitude-modulated time courses and spectra + ciftisave(PFMTCSorig, [StudyFolder '/' Subjlist{s} '/MNINonLinear/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.' OutputSTRING RegString '_ts_orig.' LowResMesh 'k_fs_LR.sdseries.nii'], wbcommand); + ciftisave(PFMSpectraorig, [StudyFolder '/' Subjlist{s} '/MNINonLinear/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.' OutputSTRING RegString '_spectra_orig.' LowResMesh 'k_fs_LR.sdseries.nii'], wbcommand); + + ciftisave(PFMTCS, [StudyFolder '/' Subjlist{s} '/MNINonLinear/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.' OutputSTRING RegString '_ts.' LowResMesh 'k_fs_LR.sdseries.nii'], wbcommand); + ciftisave(PFMSpectra, [StudyFolder '/' Subjlist{s} '/MNINonLinear/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.' OutputSTRING RegString '_spectra.' LowResMesh 'k_fs_LR.sdseries.nii'], wbcommand); + + %% Handle maps + % restore variance + if VarNormBool + fprintf('Restoring variance\n'); + clean_VN_Name = [StudyFolder '/' Subjlist{s} '/MNINonLinear/Results/' ConcatName '/' ConcatName RegString fMRIProcSTRING '_vn.dscalar.nii']; + clean_VN = ciftiopen(clean_VN_Name, wbcommand).cdata; + mapFile = [PFMFolder '/Results.ppp/Maps/sub-' Subjlist{s} '.dscalar.nii']; + maps = ciftiopen(mapFile, wbcommand); + maps.cdata = maps.cdata .* clean_VN; + ciftisave(maps, mapFile, wbcommand); + end + + % divide out vertex area weights + if VAweightBool + fprintf('Dividing out vertex area weights\n'); + VAgray = ciftiopen([StudyFolder '/' Subjlist{s} '/T1w/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.midthickness' RegString '_va_norm.grayordinates.' LowResMesh 'k_fs_LR.dscalar.nii'], wbcommand).cdata; + mapFile = [PFMFolder '/Results.ppp/Maps/sub-' Subjlist{s} '.dscalar.nii']; + maps = ciftiopen(mapFile, wbcommand); + maps.cdata = maps.cdata ./ VAgray; + ciftisave(maps, mapFile, wbcommand); + end + + % Copy PFM maps from PFM folder to subject's MNINonLinear/fsaverage_LR space directory + copyfile([PFMFolder '/Results.ppp/Maps/sub-' Subjlist{s} '.dscalar.nii'], [StudyFolder '/' Subjlist{s} '/MNINonLinear/fsaverage_LR' LowResMesh 'k/' Subjlist{s} '.' OutputSTRING RegString '_origmaps.' LowResMesh 'k_fs_LR.dscalar.nii']); + + % clean up temporary files + if VAweightBool + delete(tmp_VAgray_file); + delete(tmp_roi_file); + delete(tmp_jnk_file); + end + end % if numel(subfMRINames) ~= 0 +end % for s = 1:numel(Subjlist) +end diff --git a/PFM/scripts/PostPROFUMO.sh b/PFM/scripts/PostPROFUMO.sh new file mode 100755 index 000000000..5c29bf014 --- /dev/null +++ b/PFM/scripts/PostPROFUMO.sh @@ -0,0 +1,112 @@ +#!/bin/bash +set -eu + +pipedirguessed=0 +if [[ "${HCPPIPEDIR:-}" == "" ]] +then + pipedirguessed=1 + export HCPPIPEDIR="$(dirname -- "$0")/../.." +fi + +source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" +source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" +g_matlab_default_mode=1 + +#description of this script to use in usage +opts_SetScriptDescription "Import PROFUMO outputs and create time courses, spectra, and maps" + +#arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] +opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder containing all subjects" +opts_AddMandatory '--subject-list' 'SubjListRaw' '100206@100307...' 'list of subject IDs separated by @s' +opts_AddMandatory '--fmri-names' 'fMRIListRaw' 'rfMRI_REST1_LR@rfMRI_REST1_RL...' 'list of fmri run names separated by @s' +opts_AddMandatory '--proc-string' 'fMRIProcSTRING' 'string' "file name component representing the preprocessing" +opts_AddMandatory '--output-fmri-name' 'OutputfMRIName' 'rfMRI_REST' "name to use for PFM pipeline outputs" +opts_AddMandatory '--output-string' 'OutputSTRING' 'string' "output string for files" +opts_AddMandatory '--surf-reg-name' 'RegName' 'MSMAll' "the registration string" +opts_AddMandatory '--low-res-mesh' 'LowResMesh' 'string' "mesh resolution" +opts_AddMandatory '--pfm-folder' 'PFMFolder' 'path' "path to PFM results folder" +opts_AddMandatory '--concat-name' 'ConcatName' 'string' "concatenated fMRI name if using multi-run data" +opts_AddMandatory '--profumo-tr' 'TR' "repetition time for PROFUMO analysis" '0.72' +opts_AddOptional '--variance-normalize' 'VarNorm' 'YES or NO' "Data were variance normalized before PROFUMO, so restore varaince (default YES)" 'YES' +opts_AddOptional '--weight-vertex-areas' 'VAweight' 'YES or NO' "Data were weighted by vertex areas before PROFUMO, so restore unweighted state (default YES)" 'YES' + +opts_AddOptional '--matlab-run-mode' 'MatlabMode' '0, 1, or 2' "defaults to $g_matlab_default_mode +0 = compiled MATLAB +1 = interpreted MATLAB +2 = Octave" "$g_matlab_default_mode" + +opts_ParseArguments "$@" +VarNormBool=$(opts_StringToBool "$VarNorm") +VAweightBool=$(opts_StringToBool "$VAweight") + + +if ((pipedirguessed)) +then + log_Err_Abort "HCPPIPEDIR is not set, you must first source your edited copy of Examples/Scripts/SetUpHCPPipeline.sh" +fi + +#display the parsed/default values +opts_ShowValues + +RegString="" +if [[ "$RegName" != "" ]] +then + RegString="_$RegName" +fi + +case "$MatlabMode" in + (0) + if [[ "${MATLAB_COMPILER_RUNTIME:-}" == "" ]] + then + log_Err_Abort "to use compiled matlab, you must set and export the variable MATLAB_COMPILER_RUNTIME" + fi + ;; + (1) + matlab_interpreter=(matlab -nodisplay -nosplash) + ;; + (2) + matlab_interpreter=(octave-cli -q --no-window-system) + ;; + (*) + log_Err_Abort "unrecognized matlab mode '$MatlabMode', use 0, 1, or 2" + ;; +esac + +IFS='@' read -a SubjList <<<"$SubjListRaw" +IFS='@' read -a fMRIList <<<"$fMRIListRaw" + +#shortcut in case the folder gets renamed +this_script_dir=$(dirname "$0") + +#matlab function arguments converted to strings +matlab_argarray=("$StudyFolder" "$SubjListRaw" "$fMRIListRaw" "$ConcatName" "$fMRIProcSTRING" "$OutputfMRIName" "$OutputSTRING" "$RegString" "$LowResMesh" "$TR" "$PFMFolder" "$VarNormBool" "$VAweightBool") + +case "$MatlabMode" in + (0) + matlab_cmd=("$this_script_dir/Compiled_PostPROFUMO/run_PostPROFUMO.sh" "$MATLAB_COMPILER_RUNTIME" "${matlab_argarray[@]}") + log_Msg "running compiled matlab command: ${matlab_cmd[*]}" + "${matlab_cmd[@]}" + ;; + (1 | 2) + #reformat argument array so matlab sees them as strings + matlab_args="" + for thisarg in "${matlab_argarray[@]}" + do + if [[ "$matlab_args" != "" ]] + then + matlab_args+=", " + fi + matlab_args+="'$thisarg'" + done + matlabcode=" + addpath('$HCPPIPEDIR/global/matlab'); + addpath('$this_script_dir'); + addpath('$HCPCIFTIRWDIR'); + PostPROFUMO($matlab_args);" + + log_Msg "running matlab code: $matlabcode" + "${matlab_interpreter[@]}" <<<"$matlabcode" + echo + ;; +esac \ No newline at end of file diff --git a/PostFreeSurfer/PostFreeSurferPipeline.sh b/PostFreeSurfer/PostFreeSurferPipeline.sh index f2e0944a8..03be00da1 100755 --- a/PostFreeSurfer/PostFreeSurferPipeline.sh +++ b/PostFreeSurfer/PostFreeSurferPipeline.sh @@ -50,27 +50,13 @@ source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/processingmodecheck.shlib" "$@" # Check processing mode requirements +#description of this script to use in usage +opts_SetScriptDescription "takes FreeSurfer output folder and converts files into HCP format/organization, etc." + log_Msg "Platform Information Follows: " uname -a "$HCPPIPEDIR"/show_version -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: takes FreeSurfer output folder and converts files into HCP format/organization, etc. - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} - defaultSigma=$(echo "sqrt(200)" | bc -l) opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder containing all subjects" "--path" diff --git a/PostFreeSurfer/PostFreeSurferPipeline_1res.sh b/PostFreeSurfer/PostFreeSurferPipeline_1res.sh index 365d4b6b3..3ed080274 100755 --- a/PostFreeSurfer/PostFreeSurferPipeline_1res.sh +++ b/PostFreeSurfer/PostFreeSurferPipeline_1res.sh @@ -26,27 +26,13 @@ source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/processingmodecheck.shlib" "$@" # Check processing mode requirements +#description of this script to use in usage +opts_SetScriptDescription "takes FreeSurfer output folder and converts files into HCP format/organization, etc." + log_Msg "Platform Information Follows: " uname -a "$HCPPIPEDIR"/show_version -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: takes FreeSurfer output folder and converts files into HCP format/organization, etc. - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} - defaultSigma=$(echo "sqrt(200)" | bc -l) #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] diff --git a/PostFreeSurfer/scripts/GenerateStructuralScenes.sh b/PostFreeSurfer/scripts/GenerateStructuralScenes.sh index e6bbdd26b..2cd2cb022 100755 --- a/PostFreeSurfer/scripts/GenerateStructuralScenes.sh +++ b/PostFreeSurfer/scripts/GenerateStructuralScenes.sh @@ -13,22 +13,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" "$@" source "$HCPPIPEDIR/global/scripts/relativePath.shlib" "$@" -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: makes QC scenes and captures for HCP FreeSurfer pipelines - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "makes QC scenes and captures for HCP FreeSurfer pipelines" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/TaskfMRIAnalysis/TaskfMRIAnalysis.sh b/TaskfMRIAnalysis/TaskfMRIAnalysis.sh index 9f187fb10..75a6ff9a2 100755 --- a/TaskfMRIAnalysis/TaskfMRIAnalysis.sh +++ b/TaskfMRIAnalysis/TaskfMRIAnalysis.sh @@ -57,29 +57,16 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/fsl_version.shlib" # Function for getting FSL version -# -------------------------------------------------------------------------------- -# Usage Description Function -# -------------------------------------------------------------------------------- +# ------------------------------------------------------- +# Usage Description +# ------------------------------------------------------- -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: Run TaskfMRIAnalysis pipeline for a subject. Pipeline will run Level1 (scan-level) analyses, and Level2 (single subject-level) analysis as specified. - -Usage: $log_ToolName arguments... -[ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "Run TaskfMRIAnalysis pipeline for a subject. Pipeline will run Level1 (scan-level) analyses, and Level2 (single subject-level) analysis as specified." -# ------------------------------------------------------------------------------ +# ------------------------------------------- # Parse Command Line Options -# ------------------------------------------------------------------------------ +# ------------------------------------------- #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/TaskfMRIAnalysis/scripts/makeSubjectTaskSummary.sh b/TaskfMRIAnalysis/scripts/makeSubjectTaskSummary.sh index ed6866b87..d35633738 100755 --- a/TaskfMRIAnalysis/scripts/makeSubjectTaskSummary.sh +++ b/TaskfMRIAnalysis/scripts/makeSubjectTaskSummary.sh @@ -55,29 +55,16 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/fsl_version.shlib" # Function for getting FSL version -# -------------------------------------------------------------------------------- -# Usage Description Function -# -------------------------------------------------------------------------------- - -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: Run TaskfMRIAnalysis pipeline for a subject. Pipeline will run Level1 (scan-level) analyses, and Level2 (single subject-level) analysis as specified. - -Usage: $log_ToolName arguments... -[ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +# ------------------------------------------- +# Usage Description +# ------------------------------------------- -# ------------------------------------------------------------------------------ +#description of this script to use in usage +opts_SetScriptDescription "Run TaskfMRIAnalysis pipeline for a subject. Pipeline will run Level1 (scan-level) analyses, and Level2 (single subject-level) analysis as specified." + +# ------------------------------------------- # Parse Command Line Options -# ------------------------------------------------------------------------------ +# ------------------------------------------- #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/fMRISurface/scripts/GenerateFMRIScenes.sh b/fMRISurface/scripts/GenerateFMRIScenes.sh index 31c98860b..d63654163 100755 --- a/fMRISurface/scripts/GenerateFMRIScenes.sh +++ b/fMRISurface/scripts/GenerateFMRIScenes.sh @@ -12,22 +12,8 @@ source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/relativePath.shlib" "$@" -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: makes QC scenes and captures for HCP fMRIVolume pipeline - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "makes QC scenes and captures for HCP fMRIVolume pipeline" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/global/scripts/ExtractFromMRFIXConcat.sh b/global/scripts/ExtractFromMRFIXConcat.sh index f0a33a8a5..192e8d878 100755 --- a/global/scripts/ExtractFromMRFIXConcat.sh +++ b/global/scripts/ExtractFromMRFIXConcat.sh @@ -11,24 +11,8 @@ fi source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: extract a specified set of runs from an MR FIX - concatenated file and reconcatenate them. Typically this is used to extract - the resting state runs from a combined task and resting state MR FIX run. - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "extract a specified set of runs from an MR FIX concatenated file and reconcatenate them. Typically this is used to extract the resting state runs from a combined task and resting state MR FIX run." #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/global/scripts/RSNregression.sh b/global/scripts/RSNregression.sh index 5e901a941..09f23a98f 100755 --- a/global/scripts/RSNregression.sh +++ b/global/scripts/RSNregression.sh @@ -13,20 +13,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: regresses group ICA spatial maps into individual data in order to obtain individual spatial maps of where the subject's similar function is - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments -} +#description of this script to use in usage +opts_SetScriptDescription "regresses group ICA spatial maps into individual data in order to obtain individual spatial maps of where the subject's similar function is" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value other than empty string if AddOptional], [compatibility flag, ...] opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder containing all subjects" diff --git a/tICA/scripts/ComputeGroupTICA.sh b/tICA/scripts/ComputeGroupTICA.sh index 89b0c4ae4..e995bae7a 100755 --- a/tICA/scripts/ComputeGroupTICA.sh +++ b/tICA/scripts/ComputeGroupTICA.sh @@ -13,22 +13,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: does stuff - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "does stuff" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/tICA/scripts/ComputeTICAFeatures.sh b/tICA/scripts/ComputeTICAFeatures.sh index 486ae6472..a5890bd1b 100755 --- a/tICA/scripts/ComputeTICAFeatures.sh +++ b/tICA/scripts/ComputeTICAFeatures.sh @@ -14,22 +14,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: does stuff - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "does stuff" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/tICA/scripts/ConcatGroupSICA.sh b/tICA/scripts/ConcatGroupSICA.sh index d39e4063a..e39ad6de5 100755 --- a/tICA/scripts/ConcatGroupSICA.sh +++ b/tICA/scripts/ConcatGroupSICA.sh @@ -13,22 +13,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: does stuff - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "does stuff" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/tICA/scripts/GroupSICA.sh b/tICA/scripts/GroupSICA.sh index 40e08789a..8cac4e9f2 100755 --- a/tICA/scripts/GroupSICA.sh +++ b/tICA/scripts/GroupSICA.sh @@ -12,22 +12,8 @@ source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@" source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: does stuff - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "does stuff" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/tICA/scripts/MIGP.sh b/tICA/scripts/MIGP.sh index c4affb1e0..51d2a5503 100755 --- a/tICA/scripts/MIGP.sh +++ b/tICA/scripts/MIGP.sh @@ -13,22 +13,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: does stuff - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments - - #do not use exit, the parsing code takes care of it -} +#description of this script to use in usage +opts_SetScriptDescription "does stuff" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...] #help info for option gets printed like "--foo=<$3> - $4" diff --git a/tICA/scripts/tICACleanData.sh b/tICA/scripts/tICACleanData.sh index 16ae27452..e1702688d 100755 --- a/tICA/scripts/tICACleanData.sh +++ b/tICA/scripts/tICACleanData.sh @@ -13,20 +13,8 @@ source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@" source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" "$@" g_matlab_default_mode=1 -#this function gets called by opts_ParseArguments when --help is specified -function usage() -{ - #header text - echo " -$log_ToolName: regresses noise group temporal ICA components out of CIFTI and optionaly volume timeseries data and optionally correct the bias legacy field - -Usage: $log_ToolName PARAMETER... - -PARAMETERs are [ ] = optional; < > = user supplied value -" - #automatic argument descriptions - opts_ShowArguments -} +#description of this script to use in usage +opts_SetScriptDescription "regresses noise group temporal ICA components out of CIFTI and optionally volume timeseries data and optionally correct the bias legacy field" #arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value other than empty string if AddOptional], [compatibility flag, ...] opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder containing all subjects"