#! /bin/tcsh -f

#
# preproc-sess - runs preprocessing (mc, spatsmooth, mkbrainmask, inorm)
#
# Original Author: Doug Greve
# CVS Revision Info:
#    $Author: greve $
#    $Date: 2007/09/25 23:57:04 $
#    $Revision: 1.15.2.2 $
#
# Copyright (C) 2002-2007,
# The General Hospital Corporation (Boston, MA). 
# All rights reserved.
#
# Distribution, usage and copying of this software is covered under the
# terms found in the License Agreement file named 'COPYING' found in the
# FreeSurfer source code root directory, and duplicated here:
# https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferOpenSourceLicense
#
# General inquiries: freesurfer@nmr.mgh.harvard.edu
# Bug reports: analysis-bugs@nmr.mgh.harvard.edu
#


set VERSION = '$Id: preproc-sess,v 1.15.2.2 2007/09/25 23:57:04 greve Exp $';

set inputargs = ($argv);
set DateStr = "`date '+%y%m%d%H%M'`"

set instem   = ();
set mcinstem   = ();
set mcoutstem  = ();
set stcinstem   = ();
set stcoutstem  = ();
set sminstem   = ();
set smoutstem  = ();
set inormstem  = ();
set maskdir    = masks
set maskstem   = brain;
set fwhm    = ();
set SliceOrder = ();
set fsd     = bold;
set rlf     = ();
set mcnthrun = ();
set mcrun    = ();
set MCPerRun = 0;
set MaskPerRun = 0;

set UpdateOnly = 1;
set DoMask   = 1;
set DoMC     = 1;
set DoSTC    = 0;
set DoSmooth = 1;
set DoInorm  = 0;

set nskip = 0; # for inorm
set nolog = 0;
set targgrp = ();

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

set PWD = `getpwdcmd`;
if($status) exit 1;

set SessList = `getsesspath $argv`;
if($status || $#SessList == 0) then
  getsesspath $argv 
  exit 1;
endif

goto parse_args;
parse_args_return:

goto check_params;
check_params_return:

set umask = `umask`;

##### Create a log file ######
if($nolog) then 
  set LF = /dev/null
else
  set logdir = log;
  mkdir -p $logdir
  if(! -e $logdir) then
    echo "WARNING: could not create $logdir"
    set LF = /dev/null
  else
    set LF = $logdir/preproc-sess.log
    if(-e $LF) mv $LF $LF.old
  endif
endif
echo "--------------------------------------------------------------"
echo "preproc-sess logfile is $LF"
echo "--------------------------------------------------------------"

echo "preproc-sess log file" >> $LF
echo $VERSION >> $LF
id            >> $LF
pwd           >> $LF
echo $0        >> $LF
echo $inputargs  >> $LF
uname -a      >> $LF
date          >> $LF

echo "instem   $instem " | tee -a $LF
echo "mc   $DoMC     $mcinstem $mcoutstem " | tee -a $LF
echo "stc  $DoSTC    $stcinstem $stcoutstem"  | tee -a $LF
echo "sm   $DoSmooth $sminstem $smoutstem "| tee -a $LF
echo "mask $DoMask   $maskstem"| tee -a $LF

set ProjectDir = `pwd`;

set StartTime = `date`;
#------------------------------------------------#
foreach sess ($SessList)
  set sessid     = `basename $sess`;
  set sessparent = `dirname $sess`;

  # Create a log file #
  if(-w .) then
    mkdir -p log
    set LF = $ProjectDir/log/preproc-$sessid-$fsd.log
    rm -f $LF
  else
    set LF = /dev/null
  endif

  echo "preproc-sess" >> $LF
  echo $sessid      >> $LF
  echo $VERSION     >> $LF
  uname -a          >> $LF
  date              >> $LF
  pwd               >> $LF
  echo $inputargs   >> $LF
  echo "ProjectDir $ProjectDir" >> $LF

  if($DoMC) then
    set cmd = (mc-sess -fstem $mcinstem -fmcstem $mcoutstem)
    set cmd = ($cmd -s $sessid -d $sessparent -fsd $fsd -new)
    if($MCPerRun)   set cmd = ($cmd -perrun)
    if($#mcnthrun)  set cmd = ($cmd -targnthrun $mcnthrun)
    if($#mcrun)     set cmd = ($cmd -targrun    $mcrun)
    if($#rlf != 0)  set cmd = ($cmd -rlf $rlf);
    if($nolog)      set cmd = ($cmd -nolog);
    if($UpdateOnly) set cmd = ($cmd -update);
    if($DoInorm)    set cmd = ($cmd -inorm);
    if(! $DoInorm)  set cmd = ($cmd -no-inorm);
    echo "$sessid MC -----------------------------" |& tee -a $LF
    date      |& tee -a $LF
    pwd       |& tee -a $LF
    echo $cmd |& tee -a $LF
    echo "----------------------------------------" |& tee -a $LF
    $cmd |& tee -a $LF
    if($status) then
      echo "ERROR: mc-sess failed" |& tee -a $LF
      exit 1;
    endif
  endif

  if($DoSTC) then
    set cmd = (stc-sess -i $stcinstem -o $stcoutstem)
    if($#SliceOrder) set cmd = ($cmd -so $SliceOrder)
    set cmd = ($cmd -s $sessid -d $sessparent -fsd $fsd)
    if($#rlf != 0)  set cmd = ($cmd -rlf $rlf);
    if($nolog)      set cmd = ($cmd -nolog);
    if($UpdateOnly) set cmd = ($cmd -update);
    echo "$sessid STC -----------------------------" |& tee -a $LF
    date      |& tee -a $LF
    pwd       |& tee -a $LF
    echo $cmd |& tee -a $LF
    echo "----------------------------------------" |& tee -a $LF
    $cmd |& tee -a $LF
    if($status) then
      echo "ERROR: mc-sess failed" |& tee -a $LF
      exit 1;
    endif
  endif

  if($DoSmooth) then
    set cmd = (spatialsmooth-sess -i $sminstem -o $smoutstem -fwhm $fwhm)
    set cmd = ($cmd -fsd $fsd -s $sessid -d $sessparent)
    if($#rlf != 0)  set cmd = ($cmd -rlf $rlf);
    if($nolog)      set cmd = ($cmd -nolog);
    if($UpdateOnly) set cmd = ($cmd -update);
    if($DoInorm)    set cmd = ($cmd -inorm);
    if(! $DoInorm)  set cmd = ($cmd -noinorm);
    echo "$sessid Smooth ------------------------" |& tee -a $LF
    date      |& tee -a $LF
    pwd       |& tee -a $LF
    echo $cmd |& tee -a $LF
    echo "----------------------------------------" |& tee -a $LF
    $cmd |& tee -a $LF
    if($status) then
      echo "ERROR: spatialsmooth-sess failed" |& tee -a $LF
      exit 1;
    endif
  endif

  if($DoInorm) then
    set cmd = (inorm-sess -funcstem $inormstem )
    set cmd = ($cmd  -fsd $fsd)
    set cmd = ($cmd -s $sessid -d $sessparent)
    set cmd = ($cmd -nskip $nskip)
    if($#rlf != 0) set cmd = ($cmd -rlf $rlf);
    if($nolog)     set cmd = ($cmd -nolog);
    echo "$sessid Inorm ------------------------" |& tee -a $LF
    date      |& tee -a $LF
    pwd       |& tee -a $LF
    echo $cmd |& tee -a $LF
    echo "----------------------------------------" |& tee -a $LF
    $cmd |& tee -a $LF
    if($status) then
      echo "ERROR: inorm-sess failed" |& tee -a $LF
      exit 1;
    endif
  endif

  if($DoMask) then
    set cmd = (mkbrainmask-sess -maskstem $maskstem)
    set cmd = ($cmd -fsd $fsd)
    set cmd = ($cmd -s $sessid -d $sessparent)
    if($nolog) set cmd = ($cmd -nolog);
    if($UpdateOnly) set cmd = ($cmd -update);
    if($MaskPerRun) set cmd = ($cmd -perrun);
    echo "$sessid Inorm ------------------------" |& tee -a $LF
    date      |& tee -a $LF
    pwd       |& tee -a $LF
    echo $cmd |& tee -a $LF
    echo "----------------------------------------" |& tee -a $LF
    $cmd |& tee -a $LF
    if($status) then
      echo "ERROR: mkbrainmask-sess failed" |& tee -a $LF
      exit 1;
    endif
  endif

end

echo "----------------------------------------" |& tee -a $LF
echo "Started at $StartTime" |& tee -a $LF
echo "Ended   at `date`"     |& tee -a $LF

echo "preproc-sess done"


exit 0

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

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

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

    case "-i":
    case "-in":
      if ( $#argv == 0) goto arg1err;
      set instem = $argv[1]; shift;
      breaksw

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    case "-nomc":
      set DoMC = 0;
      breaksw

    case "-mcperrun":
      set MCPerRun = 1;
      breaksw

    case "-maskperrun":
      set MaskPerRun = 1;
      breaksw

    case "-perrun":
      set MCPerRun = 1;
      set MaskPerRun = 1;
      breaksw

    case "-no-stc":
    case "-nostc":
      set DoSTC = 0;
      breaksw

    case "-sliceorder":
    case "-so":
      if ( $#argv == 0) goto arg1err;
      set SliceOrder = $argv[1]; shift;
      set DoSTC = 1;
      breaksw

    case "-no-smooth":
    case "-nosmooth":
      set DoSmooth = 0;
      breaksw

    case "-no-inorm":
    case "-noinorm":
      set DoInorm = 0;
      breaksw

    case "-inorm":
      set DoInorm = 1;
      breaksw

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

    case "-update":
      set UpdateOnly = 1;
      breaksw

    case "-force":
    case "-noupdate":
    case "-no-update":
      set UpdateOnly = 0;
      breaksw

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

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

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

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

    case "-g":
    case "-s":
    case "-sf":
    case "-d":
    case "-df":
      shift;
      # ignore getsesspath arguments 
      breaksw

    case "-cwd":
      # ignore getsesspath arguments 
      breaksw

    case "-umask":
      if ( $#argv == 0) goto arg1err;
      umask $1; shift;
      breaksw

    case "-gperm":
      umask 02;
      breaksw

    case "-ugroup":
      if ( $#argv == 0) goto arg1err;
      set targgrp = $1; shift;
      breaksw

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

end

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

############--------------##################
check_params:
  if($#targgrp) then
    set curgrp = `id -gn`
    if($targgrp != $curgrp) then
      echo "ERROR: your current unix group is $curgrp, but your desired "
      echo "       target group is $targgrp. Change to the new group"
      echo "       with 'newgrp $targgrp' then re-run"
      exit 1;
    endif
  endif

  if($#instem == 0) set instem = "f";

  if($DoMC) then
    if($#mcinstem  == 0) set mcinstem  = $instem
    if($#mcoutstem == 0) set mcoutstem = $mcinstem"mc"
  else
    set mcoutstem = $instem;
  endif

  if($DoSTC) then
    if($#stcinstem  == 0) set stcinstem  = $mcoutstem
    if($#stcoutstem == 0) set stcoutstem = $stcinstem"stc"
  else
    set stcoutstem = $mcoutstem
  endif

  if($DoSmooth) then
    if($#fwhm == 0) then
      echo "ERROR: must specify FWHM when doing smoothing"
      echo "If not smoothing, use -nosmooth"
      exit 1;
    endif
    if($#sminstem  == 0) set sminstem  = $stcoutstem
    if($#smoutstem == 0) set smoutstem = $sminstem"sm"$fwhm
  endif

  if($DoInorm && $#inormstem == 0) then
    if($DoSmooth) then
      set inormstem = $smoutstem;
    else if($DoMC) then
      set inormstem = $mcoutstem;
    else
      set inormstem = $mcinstem;
    endif
  endif

  if($MCPerRun && $#mcnthrun ) then
    echo "ERROR: cannot specify both -mcperrun and -mcnthrun"
    exit 1;
  endif

  if($MCPerRun && $#mcrun ) then
    echo "ERROR: cannot specify both -mcperrun and -mcrun"
    exit 1;
  endif

  if($#rlf != 0 && $MCPerRun) then
    echo "ERROR: cannot specify both -rlf and -mcperrun"
    exit 1;
  endif

  if(! $DoMC && ! $DoSTC  && ! $DoSmooth && ! $DoMask) then
    echo "ERROR: nothing to do"
    exit 1;
  endif


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

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

############--------------##################
usage_exit:
  echo ""
  echo "USAGE: preproc-sess"
  echo ""
  echo "  -i    instem   : stem to use as overal input <f>"
  echo "  -fwhm fwhm     : 3D fwhm (mm)"
  echo "  -sliceorder so : turn on slice timing correction with the given slice order"
  echo "  -update        : only run a stage if input is newer than output (default)"
  echo "  -force         : force reprocessing of all stages (turns off -update)"
  echo "  -no-update     : same as -force"
  echo ""
  echo "  -nomc     : don't do motion correction"
  echo "  -nostc    : don't do slice-timing correction"
  echo "  -nosmooth : don't do smoothing"
  echo "  -nomask   : don't make brain mask"
  echo "  -noinorm  : don't do inorm"
  echo ""
  echo "  -mcin   mcinstem    : stem to use as input  to MC"
  echo "  -mcout  mcoutstem   : stem to use as output of MC"
  echo "  -stcin  stcinstem   : stem to use as input  to STC "
  echo "  -stcout stcoutstem  : stem to use as output of STC "
  echo "  -smin   sminstem    : stem to use as input  to smoothing "
  echo "  -smout  sminstem    : stem to use as output of smoothing "
  echo "  -mask   maskstem    : <brain>"
  echo ""
  echo "  -inorm        : perform intensity normalization (off by default)"
  echo "  -nskip N      : do not use first N TRs when inorming"
  echo ""
  echo "  -mcperrun : perform motion correction on all runs separately"
  echo "  -mcnthrun nthrun : use nthrun as reference"
  echo "  -mcrun    RRR    : use run RRR as reference"
  echo "  -maskperrun : perform masking on all runs separately"
  echo ""
  echo "  -perrun : perform masking and MC on all runs separately"
  echo ""
  echo "Session Arguments (Required)"
  echo "  -sf sessidfile  ..."
  echo "  -df srchdirfile ..."
  echo "  -s  sessid      ..."
  echo "  -d  srchdir     ..."
  echo "  -fsd    fsd <bold>"
  echo "  -rlf    rlf  : run list file (default all runs)"
  echo ""
  echo "Other options"
  echo "  -gperm : use group-writable unix permissions"
  echo "  -ugroup group : desired unix group"
  echo ""
  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 will run preprocessing steps: motion correction (MC),
slice-timing correction (STC), smoothing, intensity normalization
(INorm), and brain mask creation. By default, it will perform MC,
smoothing, and masking, but not STC or INorm. All stages producde a
new volume that can be used as input to mkanalysis-sess. Note: MC and
INorm require matlab but none of the other stages does.  By default,
motion correction uses the first volume of the first run as the
reference for all runs.

-i instem 

Explicitly specify input stem. Default is f.

-fwhm fwhm

Specify the fwhm for 3D spatial smoothing. There is not default.
The output will have "smFWHM" appened to it. Eg, for -fwhm 5, then
the output will have "sm5" appened. If you do not want to perform
smoothing, use -nosmooth. See also spatialsmooth-sess.

-sliceorder so

Perform slice-timing correction with the given slice order. Legal
values are siemens, up, down, odd, and even. Siemens slice order is
interleaved starting on the first slice for an odd number of slices or
the second slice for an even number. "up" is 1st, 2nd, 3rd,
etc. "down" is last, next to last, etc. odd is 1st, 3rd, 5th, , etc,
then 2nd, 4th, 6th, etc. "even" is 2nd, 4th, 6th, etc, then 1st, 3rd,
5th, etc.  See also stc-sess.

-force
-noupdate

Force processing of all stages regardless of what has been done
before. This turns off -update

-update

Only perform a stage if the output is newer than the input or if 
the output does not exist. This can be very convient as you
do not have to keep track of what has been done. Just specify
all the sessions and and it will figure out what needs to be 
done. This is the default behavior. See also -force.

-inorm

Turn on computing of intensity normalization factor (creates 
stem.meanval). This was necssary for the old selxavg.


INPUTS AND OUTPUTS

Unless otherwise specified, the input stem is f, and the input stems
and output stems of the other stages are automatically determined as
follows:

Input  to MC is instem (default is f)
Output of MC is mcinstem"mc"  (ie, the MC input stem with "mc" 
appended to the end)

Input  to STC is outstem of MC  
Output of STC is stcinstem"stc" (ie, the STC input stem with "stc" 
appended to the end)

Input  to smoothing is outstem of STC (or MC if no STC)
Output of smoothing is sminstem"smFWHM" (ie, the smoothing 
input stem with "sm" appended to the end and then the specified
FWHM appended to that).

When -mcperrun is used, the target volume is the middle frame.


EXAMPLE 1 
To perform MC, smoothing by fwhm of 5mm, and brain mask, run

  preproc-sess -sf sessidlist -df sessdirlist -fwhm 5

For MC the input will be f and the output will be fmc
For Smoothiing the input will be fmc and the output will be fmcsm5


EXAMPLE 2
To perform MC, STC, smoothing by fwhm of 7.1 mm, and brain mask, run

  preproc-sess -sf sessidlist -df sessdirlist -fwhm 7.1 -stc

For MC  the input will be f and the output will be fmc
For STC the input will be fmc and the output will be fmcstc
For Smoothiing the input will be fmcstc and the output will be fmcstcsm7.1



