-
Notifications
You must be signed in to change notification settings - Fork 7
Rules For Restructuring Code
The re-writing will probably be done in phases to make the code more modular.Conceptually, we are starting with a novel and eventually we want to work towards a dictionary. There are a few guidelines we can follow to make this process easier/manageable.
We are going to fit most the code into functions. The code as it stands does have some nice demarcations indicating when a certain process is occurring. For example, I pulled this from lines 524-535 in removeNuisanceRegressor.sh
###### FEAT registration correction ########################################
echo "...Fixing FEAT registration QC images."
#http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FEAT/FAQ
#ss: "How can I insert a custom registration into a FEAT analysis?"
regDir=${nuisancefeat}/reg
#Remove all FEAT files (after backup), repopulate with proper files
cp -r $regDir ${nuisancefeat}/regORIG
rm -f $regDir/*
The original creators gave helpful headers such as this one, "FEAT registration correction", to know how the code is naturally split up. For the example in this wiki, we can call this function regFix().
After giving the function a name, the next step is to find what files are called into this block of code. Here is the full block of code for our unstructured regFix() where I marked the input files/directories with (INFI)
###### FEAT registration correction ########################################
echo "...Fixing FEAT registration QC images."
#http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FEAT/FAQ
#ss: "How can I **insert** a custom registration into a FEAT analysis?"
(INFI)regDir=$indir/${nuisancefeat}/reg
#Remove all FEAT files (after backup), repopulate with proper files
cp -r $regDir $indir/${nuisancefeat}/regORIG
rm -rf $regDir
##Copy over appropriate reg directory from melodic.ica or preproc.feat processing
#If Melodic was run, copy over that version of the registration, otherwise use the portion from preprocessing
if [[ (INFI)$melFlag == 1 ]]; then
##Melodic was used (-P 2)
#Copy over "melodic" registration directory
cp -r (INFI)$indir/${melodicfeat}/reg $indir/${nuisancefeat}
else
##Melodic was not used (-P 2a)
#Copy over "preproc" registration directory
cp -r (INFI)$indir/${preprocfeat}/reg $indir/${nuisancefeat}
fi
#Backup original design file
cp (INFI)$indir/${nuisancefeat}/design.fsf $indir/${nuisancefeat}/designORIG.fsf
After looking at the files and directories the code presumes exists, we can determine what the inputs to our function regFix are going to be. One big one appears to be the directory where we want the registration to be fixed, so we want
Now that we know what's going in to our function, we can begin to write some code.
function regFix() {
local featdir=$1
local inreg=$2
....code to be written
}
Now it's time to see what our function is outputting/doing/producing. I'm going to paste the original code again, except this time I'm going to mark places that files/directories are being created with a (OUTFI).
###### FEAT registration correction ########################################
echo "...Fixing FEAT registration QC images."
#http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FEAT/FAQ
#ss: "How can I insert a custom registration into a FEAT analysis?"
regDir=$indir/${nuisancefeat}/reg
#Remove all FEAT files (after backup), repopulate with proper files
cp -r $regDir (OUTFI)$indir/${nuisancefeat}/regORIG
rm -rf $regDir
##Copy over appropriate reg directory from melodic.ica or preproc.feat processing
#If Melodic was run, copy over that version of the registration, otherwise use the portion from preprocessing
if [[ $melFlag == 1 ]]; then
##Melodic was used (-P 2)
#Copy over "melodic" registration directory
cp -r $indir/${melodicfeat}/reg (OUTFI)$indir/${nuisancefeat}
else
##Melodic was not used (-P 2a)
#Copy over "preproc" registration directory
cp -r $indir/${preprocfeat}/reg (OUTFI)$indir/${nuisancefeat}
fi
#Backup original design file
cp $indir/${nuisancefeat}/design.fsf (OUTFI)$indir/${nuisancefeat}/designORIG.fsf
The output is the reg directory populated with the correct registration files, the designORIG.fsf, and the original registration directory regORIG. Luckily all these files are under the input directory featdir making the creation of these files a relatively easy code rewrite. Thus the function would look like the following:
function regFix() {
local featdir=$1
local inreg=$2
echo "...Fixing FEAT registration QC images."
#backup the original registration into regORIG and destroy reg.
cp -r ${featdir}/reg ${featdir}/regORIG ||\
{ printf "copying the regORIG directory failed, exiting ${FUNCNAME}" && return 1 ;}
rm -rf ${featdir}/reg
#copy the preferred registration files from a user supplied regdir to the user supplied featdir
cp -r ${inreg} ${featdir} ||\
{ printf "copying the reg directory failed, exiting ${FUNCNAME}" && return 1 ;}
#Backup original design file
cp ${featdir}/design.fsf ${featdir}/designORIG.fsf ||\
{ printf "copying design.fsf failed, exiting ${FUNCNAME}" && return 1 ;}
echo "$FUNCNAME completed successfully" && return 0
}
Congrats! the function is made, and be called like this:
regFix "/subdir/func/nuisancereg.feat" "/subdir/func/preproc.feat/reg"
There may be some bits of code that you don't recognize, and that's okay, I'll cover that in another page about being a defensive programmer that loves giving informative error messages. More on that later.
There is one final step towards creating a function and this arguably the most important, creating the documentation. A whole page can be written about this too, but I'll try to be brief. There can be 8 bits of information useful to anyone wanting to use your function. They are as follows: function: the name of your function purpose: what does the function do at a high level (conceptual level)? input: what files,directories,flags do you pass into the function? preconditions: what does the function assume about the input you passed into it? output: what does the function produce/make? dependencies: what other software/functions does this function need to work properly? Used in: where can find this function being used?
With this in mind, we can take a stab at writing the documentation of the function we just created.
##################
#function: regFix
##################
#purpose: Copies the reg directory from one featdir to another.
##################
#preconditions: feat has been ran on the input directory, and that the gold standard registration exists
##################
#input (typical): /subj/func/nuisancereg.feat (a feat directory)
# /subj/func/preproc.feat/reg (a gold standard registration directory)
##################
#output: /subj/func/nuisancereg.feat/regORIG
# /subj/func/nuisancereg.feat/designORIG.fsf
# /subj/func/nuisancereg.feat/reg/<whatever are the different files>
##################
#dependencies: None <besides what comes with standard bash>
##################
#Used in: MAIN <the main script that isn't a part of a function>
##################
Now you have some of the tools to begin restructuring the code to a function format! Please see dataPrep.sh and qualityCheck.sh for more examples.
Definition of how to fill out parameters
##################
#function: <function name>
##################
#purpose: <what specific task does this function complete?>
##################
#preconditions: <what about the inputs do we assume?>
##################
#input (typical): <what inputs does the function take in?>
##################
#output: <what files the function creates or what output it returns>
##################
#dependencies: <what software/other functions are required for this function to run>
##################
#Used in: <where is this function called? in another function or in the main portion of the script?>
##################
Template
##################
#function:
##################
#purpose:
##################
#preconditions:
##################
#input (typical):
##################
#output:
##################
#dependencies:
##################
#Used in:
##################