#!/usr/bin/tcsh -f
# fs-topup - sources
if(-e $FREESURFER_HOME/sources.csh) then
  source $FREESURFER_HOME/sources.csh
endif

set VERSION = '$Id$';
set scriptname = `basename $0`
setenv IGNORE_TAG_RAS_XFORM

# The topup config depends on the number of slices. Eg, if odd, then
# use b02b0_1.cnf; if even then b02b0_2.cnf = b02b0.cnf, and topup
# will die if you give it the wrong one. However, if you don't give topup
# a config file at all, it will not die, though I'm not sure if it will
# do the right thing
set config = ()
set configodd  = /usr/pubsw/packages/fsl/6.0.1/src/topup/flirtsch/b02b0_1.cnf
set configeven = /usr/pubsw/packages/fsl/6.0.1/src/topup/flirtsch/b02b0_2.cnf
set UseConfig = 1 # 

set outdir = ();
set b0dc = ()
set subject = ();
set ForceUpdate = 0
set threads = 1
set vols = ()
set DoQA = 0
set ndilations = 1
set DoMask = 1
set params = ()
set MultiFrame = 1 # 1=compute mean, 2=take first frame
# Total readout time in sec. If TRT=1, then b0 map will be in voxels,
# otherwise in Hz. The choice of TRT will have two implications: (1)
# if the number is wrong, then the Hz value will be wrong. (2) if
# combining with FSL eddy, then it needs to be consistent. Note that
# FSL eddy typically fails when TRT=1. The choice itself will not 
# have an effect on the B0-corrected maps.
set TRT = 1 

set tmpdir = ();
set cleanup = 1;
set LF = ();

set inputargs = ($argv);
set PrintHelp = 0;
if($#argv == 0) goto usage_exit;
set n = `echo $argv | grep -e -help | wc -l` 
if($n != 0) then
  set PrintHelp = 1;
  goto usage_exit;
endif
set n = `echo $argv | grep -e -version | wc -l` 
if($n != 0) then
  echo $VERSION
  exit 0;
endif
goto parse_args;
parse_args_return:
goto check_params;
check_params_return:
setenv OMP_NUM_THREADS $threads

set StartTime = `date`;
set tSecStart = `date '+%s'`;
set year  = `date +%Y`
set month = `date +%m`
set day   = `date +%d`
set hour   = `date +%H`
set min    = `date +%M`

mkdir -p $outdir/log
if($#subject) mkdir -p $outdir/reg
pushd $outdir > /dev/null
set outdir = `pwd`;
popd > /dev/null

if($#tmpdir == 0) then
  if(-dw /scratch)   set tmpdir = /scratch/tmpdir.fs-topup.$$
  if(! -dw /scratch) set tmpdir = $outdir/tmpdir.fs-topup.$$
endif
#mkdir -p $tmpdir

# Set up log file
if($#LF == 0) set LF = $outdir/log/fs-topup.Y$year.M$month.D$day.H$hour.M$min.log
if($LF != /dev/null) rm -f $LF
echo "Log file for fs-topup" >> $LF
date  | tee -a $LF
echo "" | tee -a $LF
echo "setenv SUBJECTS_DIR $SUBJECTS_DIR" | tee -a $LF
echo "cd `pwd`"  | tee -a $LF
echo $0 $inputargs | tee -a $LF
ls -l $0  | tee -a $LF
echo "" | tee -a $LF
cat $FREESURFER_HOME/build-stamp.txt | tee -a $LF
echo $VERSION | tee -a $LF
uname -a  | tee -a $LF
echo "pid $$" | tee -a $LF
if($?PBS_JOBID) then
  echo "pbsjob $PBS_JOBID"  >> $LF
endif
if($?SLURM_JOB_ID) then
  echo SLURM_JOB_ID $SLURM_JOB_ID >> $LF
endif

if($UseConfig && $#config == 0) then
  # Get number of slices
  set tmpfile = /tmp/fs-topup.$$
  mri_info --o $tmpfile --dim $vols[1] 
  if($status) exit 1
  set dim = `cat $tmpfile`
  rm $tmpfile
  set nslices = $dim[3];
  set IsOdd = `python -c "print($nslices%2)"`
  echo "Dim: $dim  IsOdd $IsOdd" | tee -a $LF
  if($IsOdd) then
    set config = $configodd
  else
    set config = $configeven
  endif
endif

# Check for multiple frames. If so, compute the mean.  Should also do
# motion correction? Might not be needed as these scans are usually
# pretty quick.
set nframes = ()
set vols2 = ()
@ n = 0
foreach v ($vols)
  @ n = $n + 1
  set nframesfile = $outdir/log/nframes$n.dat
  set ud = `UpdateNeeded $nframesfile $v`
  if($ud || $ForceUpdate) then
    set cmd = (mri_info --nframes --o $nframesfile $v)
    echo $cmd | tee -a $LF
    $cmd | tee -a $LF
    if($status) goto error_exit
  endif
  set nf = `cat $nframesfile`
  set nframes = ($nframes $nf)
  if($nf > 1 && $MultiFrame) then
    set vmn = $outdir/vol$n.nii.gz
    set ud = `UpdateNeeded $vmn $v`
    if($ud || $ForceUpdate) then
      if($MultiFrame == 1) set cmd = (mri_concat  $v --mean --o $vmn)
      if($MultiFrame == 2) set cmd = (mri_convert $v --frame 0  $vmn)
      echo $cmd | tee -a $LF
      $cmd | tee -a $LF
      if($status) goto error_exit
    endif
    set vols2 = ($vols2 $vmn)
  else
    if($nf > 1 && $#params == 0) then
      echo "ERROR: multiframe data needs either --p or allowing of multiframemean"
      exit 1
    endif
    set vols2 = ($vols2 $v)
  endif
end
set vols = ($vols2)

# Concatenate the two directions (will be more if multiple frames allowed)
set both = $outdir/both.nii.gz
set ud = `UpdateNeeded $both $vols`
if($ud || $ForceUpdate) then
  set cmd = (mri_concat $vols --o $both)
  echo "\n" $cmd | tee -a $LF
  $cmd |& tee -a $LF
  if($status) goto error_exit
endif

# This indicates the phase encode direction. Below is for AP then
# PA. See also BBR command.  When running vol2vol or vol2surf or bbr
# on the 2nd volume have to change the PE dir. Note that when used
# with FSL eddy, this needs to be consistent.
if($#params == 0) then
  set params = $outdir/params.dat
  if(! -e $params) then
    echo "0  1 0 $TRT" > $params
    echo "0 -1 0 $TRT" >> $params
  endif
else
  cp $params $outdir/log
endif

# Determine if TRT=1
set TRTis1 = `echo "sqrt((1-$TRT)*(1-$TRT)) < .0001" | bc -l`

set b0dcnomask = $outdir/b0dc.nomask.nii.gz # vox if TRT=1, Hz otherwise
set bothb0dc = $outdir/both.b0dc.nii.gz
set ud = `UpdateNeeded $b0dcnomask $both`
if($ud || $ForceUpdate) then
  # Run FSL topup
  set cmd = (fs_time topup --imain=$both --datain=$params --out=$outdir \
   --fout=$b0dcnomask --iout=$bothb0dc)
  if($#config) set cmd = ($cmd --config=$config)
  if($threads > 1) set cmd = ($cmd --nthr=$threads) # FSL>=6.0.6, not sure it works
  echo "fsl-topup-command"  | tee -a $LF # makes it easier to find in log file
  echo "\n" $cmd | tee -a $LF
  fs_time $cmd |& tee -a $LF
  if($status) then
    if($threads > 1) then
      echo "If this error has to do with the --nthr topup option, then make sure you are using FSL>=6.0.6" | tee -a $LF
    endif
    goto error_exit
  endif
  # annoyingly creates ${outdir}_fieldcoef.nii.gz ${outdir}_movpar.txt
  # Move them to the output folder. Add "topup_" as a prefix so that
  # other FSL commands can take $outdir/topup as the topup argument.
  mv ${outdir}_fieldcoef.nii.gz $outdir/topup_fieldcoef.nii.gz 
  mv ${outdir}_movpar.txt $outdir/topup_movpar.txt
endif

# Compute the mean of the two (or more) corrected volumes
set meanb0dc = $outdir/mean.b0dc.nii.gz
set ud = `UpdateNeeded $meanb0dc $bothb0dc`
if($ud || $ForceUpdate) then
  set cmd = (mri_concat $bothb0dc --mean --o $meanb0dc)
  echo "\n" $cmd | tee -a $LF
  $cmd |& tee -a $LF
  if($status) goto error_exit
endif

if($DoMask) then
  # Create a mask in the corrected space
  set maskb0dc = $outdir/mask.b0dc.nii.gz
  set ud = `UpdateNeeded $maskb0dc $meanb0dc`
  if($ud || $ForceUpdate) then
    set cmd = (fs_time mri_synthstrip -i $meanb0dc -m $maskb0dc -t $threads)
    echo "\n" $cmd | tee -a $LF
    $cmd | tee -a $LF
    if($status) goto error_exit
    if($ndilations > 0) then
      set cmd = (mri_binarize --i $maskb0dc --min 0.5 --dilate $ndilations --o $maskb0dc)
      echo "\n" $cmd | tee -a $LF
      $cmd | tee -a $LF
      if($status) goto error_exit
    endif
  endif
  # Now mask the B0map volume
  set b0dc = $outdir/b0dc.nii.gz
  set ud = `UpdateNeeded $b0dc $maskb0dc $b0dcnomask`
  if($ud || $ForceUpdate) then
    set cmd = (mri_mask $b0dcnomask $maskb0dc $b0dc)
    echo "\n" $cmd | tee -a $LF
    $cmd |& tee -a $LF
    if($status) goto error_exit
  endif
else
  set b0dc = $b0dcnomask
endif

# Create vox and hz maps depending upon TRT
set vsm = $outdir/b0dc.vox.nii.gz
if($TRTis1) then
  # If TRT is 1.0, then b0dc is the voxel shift map (VSM)
  pushd $outdir
  ln -fs b0dc.nii.gz b0dc.vox.nii.gz
  popd
else
  # If TRT is not 1.0, then b0dc is in Hz
  pushd $outdir
  ln -fs b0dc.nii.gz b0dc.hz.nii.gz
  popd
  # Create a VSM by multiplying Hz by TRT.
  set ud = `UpdateNeeded $vsm $b0dc`
  if($ud || $ForceUpdate) then
    set cmd = (fscalc $b0dc -mul $TRT -o $vsm)
    echo "\n" $cmd | tee -a $LF
    $cmd |& tee -a $LF
    if($status) goto error_exit
  endif
endif

if($DoQA == 2) then
  # This is a comparison of how FS vs FSL apply the B0 map.  Compare
  # both.b0dc.nii (the fsl-corrected vols) to v1.qa and v2.qa.
  # both.b0dc.nii has two frames corresponding to v1 and v2.  Note:
  # vol2vol will not do jacobian correction whereas topup will, so you
  # might see some bright spots in the FSL output. When I examined
  # these more carefully, FS and FSL were both very close, but I
  # thought FS was better for v2 but FSL was better for v1; bbregister
  # mincost agrees. Not sure what is going on. The RMS diff in the
  # registrations is 0.4mm and 0.3mm, so not such a big deal
  # Not that useful so have to spec --qa2
  mkdir -p $outdir/qa
  foreach v (1 2) # might not be perfect with multiple frames
    set vb0dc = $outdir/qa/v$v.qa.nii.gz
    set ud = `UpdateNeeded $vb0dc $vols[$v] $b0dc` 
    if($ud || $ForceUpdate) then
      set cmd = (mri_vol2vol --mov $vols[$v] --targ $meanb0dc --regheader --vsm $vsm --o $vb0dc)
      if($v == 2) set cmd = ($cmd --vsm-pedir -2)
      echo "\n" $cmd | tee -a $LF
      $cmd |& tee -a $LF
      if($status) goto error_exit
    endif
  end
endif

if($#subject) then
  # If a subject was passed, then run BBR, mostly to do QA in that the mincost
  # should be lower after correction
  set mov = $meanb0dc
  set regmean = $outdir/reg/reg.mean.b0dc.lta
  set ud = `UpdateNeeded $regmean $mov` # should add b0dc
  if($ud || $ForceUpdate) then
    set cmd = (bbregister --s $subject --mov $mov --bold --reg $regmean --threads $threads)
    echo "\n" $cmd | tee -a $LF
    $cmd |& tee -a $LF
    if($status) goto error_exit
  endif
 
  if($DoQA) then
    foreach v (1 2) # might not be perfect with multiple frames
      foreach c (nob0dc b0dc)
        set reg = $outdir/reg/reg.v$v.$c.lta
        set mov = $vols[$v]
        set vsmopt = ""
        if($c == b0dc) set vsmopt = "--vsm $vsm"
        set ud = `UpdateNeeded $reg $mov` # should add b0dc
        if($ud || $ForceUpdate) then
          set cmd = (bbregister --s $subject --mov $mov --bold --reg $reg $vsmopt \
            --init-reg $regmean --threads $threads)
          if($v == 2) set cmd = ($cmd --vsm-pedir -2)
          echo "\n" $cmd | tee -a $LF
          $cmd |& tee -a $LF
          if($status) goto error_exit
        endif
      end # cor
    end # vol
  endif # QA
endif

#========================================================

# Cleanup
# if($cleanup) rm -rf $tmpdir

# Done
echo " " |& tee -a $LF
set tSecEnd = `date '+%s'`;
@ tSecRun = $tSecEnd - $tSecStart;
set tRunMin = `echo $tSecRun/60|bc -l`
set tRunMin = `printf %5.2f $tRunMin`
set tRunHours = `echo $tSecRun/3600|bc -l`
set tRunHours = `printf %5.2f $tRunHours`
echo "Started at $StartTime " |& tee -a $LF
echo "Ended   at `date`" |& tee -a $LF
echo "Fs-Topup-Run-Time-Sec $tSecRun" |& tee -a $LF
echo "Fs-Topup-Run-Time-Min $tRunMin" |& tee -a $LF
echo "Fs-Topup-Run-Time-Hours $tRunHours" |& tee -a $LF
echo " " |& tee -a $LF
echo "fs-topup Done" |& tee -a $LF
exit 0

###############################################

############--------------##################
error_exit:
echo "ERROR:"

exit 1;
###############################################

############--------------##################
parse_args:
set cmdline = ($argv);
while( $#argv != 0 )

  set flag = $argv[1]; shift;
  
  switch($flag)

    case "--o":
      if($#argv < 1) goto arg1err;
      set outdir = $argv[1]; shift;
      breaksw

    case "--s":
      if($#argv < 1) goto arg1err;
      set subject = $argv[1]; shift;
      breaksw

    case "--sd":
      if($#argv < 1) goto arg1err;
      setenv SUBJECTS_DIR $argv[1]; shift;
      breaksw

    case "--threads":
      if($#argv < 1) goto arg1err;
      set threads = $argv[1]; shift;
      breaksw

    case "--trt":
      if($#argv < 1) goto arg1err;
      set TRT = $argv[1]; shift;
      breaksw

    case "--ndil":
    case "--ndilations":
      if($#argv < 1) goto arg1err;
      set ndilations = $argv[1]; shift;
      breaksw

    case "--i":
      if($#argv < 2) goto arg2err;
      set vols = ($argv[1] $argv[2]);
      shift;shift;
      breaksw

    case "--config":
      if($#argv < 1) goto arg1err;
      set config = $argv[1]; shift
      set UseConfig = 1
      breaksw

    case "--no-config":
      set UseConfig = 0
      breaksw

    case "--config-odd":
      set config = $configodd
      breaksw

    case "--config-even":
      set config = $configeven
      breaksw

    case "--p":
      if($#argv < 1) goto arg1err;
      set params = $argv[1]; shift
      breaksw

    case "--multi-frame-mean":
      set MultiFrame = 1
      breaksw
    case "--multi-frame-first":
      set MultiFrame = 2
      breaksw
    case "--no-multi-frame":
      set DoMultiFrameMean = 0
      breaksw

    case "--qa":
      set DoQA = 1
      breaksw
    case "--qa2":
      set DoQA = 2
      breaksw

    case "--no-mask":
      set DoMask = 0
      breaksw

    case "--force":
     set ForceUpdate = 1
     breaksw
    case "--no-force":
     set ForceUpdate = 0
     breaksw

    case "--log":
      if($#argv < 1) goto arg1err;
      set LF = $argv[1]; shift;
      breaksw

    case "--nolog":
    case "--no-log":
      set LF = /dev/null
      breaksw

    case "--tmp":
    case "--tmpdir":
      if($#argv < 1) goto arg1err;
      set tmpdir = $argv[1]; shift;
      set cleanup = 0;
      breaksw

    case "--nocleanup":
      set cleanup = 0;
      breaksw

    case "--cleanup":
      set cleanup = 1;
      breaksw

    case "--debug":
      set verbose = 1;
      set echo = 1;
      breaksw

    default:
      echo ERROR: Flag $flag unrecognized. 
      echo $cmdline
      exit 1
      breaksw
  endsw

end

goto parse_args_return;
############--------------##################

############--------------##################
check_params:

if($#outdir == 0) then
  echo "ERROR: must spec outdir"
  exit 1;
endif
if($#vols == 0) then
  echo "ERROR: must spec input volumes"
  exit 1;
endif
if($#subject) then
  if(! -e $SUBJECTS_DIR/$subject) then
    echo "ERROR: cannot find $subject"
    exit 1;
  endif
else
  if($DoQA) then
    echo "ERROR: must specify --s subject with --qa"
    exit 1;
  endif
endif

if($#config) then
  if(!-e $config) then
    echo "ERROR: cannot find $config"
    exit 1
  endif
  if($UseConfig == 0) then
    echo "ERROR: cannot spec both --config and --no-config"
    exit 1
  endif
endif

if($#params) then
  if(! -e $params) then
    echo "ERROR: cannot find $params"
    exit 1
  endif
endif

#if($DoQA && $TRT != 1) then
#  echo "ERROR: TRT = $TRT, cannot use --qa if TRT != 1"
#  exit 1
#endif

which topup >& /dev/null
if($status) then
  echo "ERROR: cannot find topup in the path."
  echo " Do you have FSL installed and in your path?"
  exit 1
endif

goto check_params_return;
############--------------##################

############--------------##################
arg1err:
  echo "ERROR: flag $flag requires one argument"
  exit 1
############--------------##################
arg2err:
  echo "ERROR: flag $flag requires two arguments"
  exit 1
############--------------##################

############--------------##################
usage_exit:
  echo ""
  echo "fs-topup - FS front end for FSL's topup (developed under FSL 6.0.5.1)"
  echo " --i vol1 vol2 : vol1 and vol2 have opposite phase encodings"
  echo " --o outdir"
  echo " --ndilations ndil : dilate mask"
  echo " --no-mask : do not mask the B0 map"
  echo " --s subject : register B0-corrected to subject (also needed for QA using mincost)"
  echo " --config topup.cfn : topup config file (does not use a config file by default)"
  echo " --config-{odd,even}: use b02b0_{1,2}.cnf"
  echo " --p params : parameter file passed to topup (default is assuming AP/PA)"
  echo " --no-multi-frame-mean : do not comute the mean of multi-frame inputs (will need a param file)"
  echo " --qa : bbregister with and without B0DC to assure that the cost goes down (needs --s)"
  echo  "  Note: this can add 5-10min onto this script's execution time"
  echo " --trt total readout time in sec (default is $TRT)" 
  echo " --multi-frame-mean : compute the mean of multi-frame inputs"
  echo " --multi-frame-first : extract the first frame of multi-frame inputs"
  echo " --no-multi-frame : do not do anything to multi-frame inputs (requires --p)"
  echo " --threads nthreads : does not appear to help much with topup"
  echo ""

  if(! $PrintHelp) exit 1;
  echo $VERSION
  cat $0 | awk 'BEGIN{prt=0}{if(prt) print $0; if($1 == "BEGINHELP") prt = 1 }'
exit 1;

#---- Everything below here is printed out as part of help -----#
BEGINHELP

This program is a FreeSurfer frontend for for FSLs topup B0
distortion correction command (developed under FSL 6.0.5.1). It
collects the inputs, runs topup, creates a mask using synthstrip,
registers to FreeSurfer subject (if supplied). See also fs-eddytopper.

There will be (possibly) three output B0 maps: b0dc.nii.gz,
b0dc.vox.nii.gz, b0dc.hz.nii.gz.  If TRT is set to a value different
than 1, then b0dc.nii.gz will be in Hz and b0dc.hz.nii.gz will be a
symlink pointing to b0dc.nii.gz. Note that TRT must be set accurately
for the Hz values to be accurate (see below).  If TRT=1, then
b0dc.nii.gz will be in voxels and b0dc.vox.nii.gz will be a symlink
pointing to b0dc.nii.gz (and b0dc.hz.nii.gz) will not exit. Note that
b0dc.vox.nii.gz will always be right regardless of TRT. Note that
these maps will have been masked unless --no-mask is used. There is an
output b0dc.nomask.nii.gz (in either Hz or vox depending upon TRT).

Setting the total readout time (TRT). The proper value will be TRT =
EPIFactor * EchoSpacing * PartialFourier / AccelFactor, where the
EchoSpacing is in seconds.  Eg, TRT = 116*0.58ms*.001/2 = 0.0336
seconds. If the TRT is not set correctly, the only implication is that
the Hz values will be wrong.  It will still apply the proper
correction and the voxel shift map will still be right. Note that SMS
acceleration does not reduce the effective echo spacing.

Note that topup will register the second input volume (ie, the
reversed phase encode direction) to the first and the output maps will
be in the (undistored) space of the first volume. This allows for the
reversed phase encoded image to be acquired at a different time as the
series to be corrected. For this application, one would then take the
first frame from the series as the non-reversed input (first input
volume). 

If you are going to use the output in conjunction with other
FreeSurfer programs, eg, FSFAST or bbregister, then pass those
programs the b0dc.vox.nii.gz as the --vsm argument. Within the FSFAST
structure, copy or link b0dc.vox.nii.gz to sess/fsd/b0dcmap.nii.gz.

If you are going to use the output with other FSL programs, then 
pass outdir/topup as the topup input.

When using in conjunction with FSLs eddy for DTI analysis, the first
volume input to topup must be the same as the first volume in --imain
to eddy_correct and the TRT must be consistent (as does the
acquisition parameter file). According to the eddy FAQ
https://fsl.fmrib.ox.ac.uk/fsl/docs/diffusion/eddy/FAQ/index.html the
TRT value does not matter that much. As long as it is consistent
between topup and eddy, they give indistinguishable results. However,
eddy may crash if TRT is too low (~<.01) or too high (~>.9).  Also see
fs-eddytopper.

The topup config depends on the number of slices. Eg, if odd, then use
b02b0_1.cnf; if even then b02b0_2.cnf = b02b0.cnf, and topup will die
if you give it the wrong one. By default, fs-topup will look at the
number of slices and choose the right one. Note: if you dont give
topup a config file at all, it will not die, though Im not sure if it
will do the right thing.

When passing a subject, it will create outdir/reg/reg.mean.b0dc.lta
which is the BBR registration of the mean of the two B0-corrected
inputs.

Quality Assurance (QA): if you add the --qa option with --s, then
fs-topup will register each of the input volumes to the FreeSurfer
anatomical using bbregister with and without B0 correction. If the B0
correction is working, then the best BBR cost should decrease. There
will be a reg folder in the output folder with the followinng files:

reg.v1.b0dc.dat.mincost
reg.v1.nob0dc.dat.mincost
reg.v2.b0dc.dat.mincost
reg.v2.nob0dc.dat.mincost

v1 is for the first input volume and v2 for the second.  The first
value in each file is the minimum cost found by BBR. The value in the
b0dc file should be less than that in the corresponding nob0dc
file. If not, then something went wrong. This is something you must
check yourself; fs-topup will not throw an error. These registrations
may add 5-10min on the execution time for fs-topup, so you may want to
try it on a few cases to convince yourself it is doing the right thing
then leave it off.

If either vol1 or vol2 has multiple frames, then the mean across
frames is computed and used. The first frame can be used instead by
specifying --multi-frame-first. 

CITATION: From: https://fsl.fmrib.ox.ac.uk/fsl/docs/diffusion/topup/index.html

If you use topup in your research, please make sure that you reference
at least the first of the articles listed below, and ideally both.
For your convenience, we provide example text (short and more details
versions), which you are welcome to use in your methods description.

Brief summary text: "Data was collected with reversed phase-encode
blips, resulting in pairs of images with distortions going in opposite
directions. From these pairs the susceptibility-induced off-resonance
field was estimated using a method similar to that described in
[Andersson 2003] as implemented in FSL [Smith 2004] and the two images
were combined into a single corrected one."

[Andersson 2003] J.L.R. Andersson, S. Skare, J. Ashburner How to
correct susceptibility distortions in spin-echo echo-planar images:
application to diffusion tensor imaging. NeuroImage, 20(2):870-888,
2003.

[Smith 2004] S.M. Smith, M. Jenkinson, M.W. Woolrich, C.F. Beckmann,
T.E.J. Behrens, H. Johansen-Berg, P.R. Bannister, M. De Luca,
I. Drobnjak, D.E. Flitney, R. Niazy, J. Saunders, J. Vickers,
Y. Zhang, N. De Stefano, J.M. Brady, and P.M. Matthews. Advances in
functional and structural MR image analysis and implementation as
FSL. NeuroImage, 23(S1):208-219, 2004.

