#!/usr/bin/tcsh -f

#
# make_average_subject
#
# Creates average surfaces, curvatures, and volumes from a set of subjects.
#
# --help option will show usage
#
# Original Author: Doug Greve
#
# Copyright © 2021 The General Hospital Corporation (Boston, MA) "MGH"
#
# Terms and conditions for use, reproduction, distribution and contribution
# are found in the 'FreeSurfer Software License Agreement' contained
# in the file 'LICENSE' found in the FreeSurfer distribution, and here:
#
# https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
#
# Reporting: freesurfer@nmr.mgh.harvard.edu
#
#

# uncomment this to increase number of allowable open files:
#limit descriptors unlimited

set VERSION = 'make_average_subject mockbuild-local';
set PrintHelp = 0;
set sdout = ();
set average_subject = ();
set DoLink = 0;
set DoSurfaces = 1;
set DoVolumes  = 1;
set Force = 0;
set KeepAllOrig = 0;
set DoRibbon = 1
set hemilist = (lh rh);
set rcathreads = 1
# Turn off requirement to match version
setenv REQUIRE_FS_MATCH 0


set cmdargs = ($argv);

if($#argv == 0) then
  # zero args is allowed only if SUBJECTS env var is declared
  if ( ! $?SUBJECTS) then
    goto usage_exit;
  endif
endif

source $FREESURFER_HOME/sources.csh

goto parse_args;
parse_args_return:
goto check_params;
check_params_return:

pushd $sdout > /dev/null
set sdoutfulldir = `pwd`;
popd > /dev/null

mkdir -p $sdoutfulldir/$average_subject/scripts
set LF = $sdoutfulldir/$average_subject/scripts/make_average_subject.log
if(-e $LF) mv $LF $LF.bak

echo "" | tee -a $LF
echo "setenv SUBJECTS_DIR $SUBJECTS_DIR" | tee -a $LF
echo $0 $cmdargs | tee -a $LF
echo "" | tee -a $LF
echo $VERSION | tee -a $LF
date | tee -a $LF
pwd | tee -a $LF
echo "output ddir is $sdout" | tee -a $LF
id | tee -a $LF

if($DoLink) then
  echo "Creating link"
  pushd $SUBJECTS_DIR > /dev/null
  set cmd = (ln -s $sdoutfulldir/$average_subject $average_subject)
  echo $cmd| tee -a $LF
  $cmd| tee -a $LF
  if($status) then
    echo "ERROR: make_average_subject"
    exit 1;
  endif
  popd > /dev/null
endif

if($DoVolumes) then
  # Do volumes first so that there is a volgeom template for surfaces
  set cmd = (make_average_volume $cmdargs)
  if($KeepAllOrig) set cmd = ($cmd --keep-all-orig)
  echo $cmd | tee -a $LF
  $cmd
  if($status) then
    echo "ERROR: make_average_volume"| tee -a $LF
    exit 1;
  endif
endif

if($DoSurfaces) then
  set cmd = (make_average_surface $cmdargs)
  echo $cmd | tee -a $LF
  $cmd
  if($status) then
    echo "ERROR: make_average_surface"| tee -a $LF
    exit 1;
  endif
endif

if($DoSurfaces && $DoVolumes && $DoRibbon) then
  set xopts = `fs_temp_file --suffix .xopts`
  set cmd = (recon-all -s $average_subject -cortribbon -aparc2aseg -threads $rcathreads)
  if($#hemilist == 1) set cmd = ($cmd -$hemilist)
  echo "mri_aparc2aseg --no-relabel" > $xopts
  set cmd = ($cmd -expert $xopts -xopts-overwrite)
  echo $cmd | tee -a $LF
  $cmd | tee -a $LF
  if($status) exit 1;
  rm $xopts
endif

date | tee -a $LF
echo "make_average_subject done" | tee -a $LF


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

while( $#argv != 0 )

  set flag = $argv[1]; shift;

  switch($flag)

    case "--help":
      set PrintHelp = 1;
      goto usage_exit;
      exit 0;
      breaksw

    case "--version":
      echo $VERSION
      exit 0;
      breaksw

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

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

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

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

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

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

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

    case "--no-link":
      set DoLink = 0;
      breaksw

    case "--lh":
      set hemilist = lh;
      breaksw;

    case "--rh":
      set hemilist = rh;
      breaksw;

    case "--link":
      set DoLink = 1;
      breaksw

    case "--no-surf":
      set DoSurfaces = 0;
      breaksw

    case "--no-ribbon":
      set DoRibbon = 0;
      breaksw

    case "--no-vol":
      set DoVolumes = 0;
      breaksw

    case "--force":
      set Force = 1;
      set DoLink = 0;
      breaksw

    case "--keep-all-orig":
      set KeepAllOrig = 1;
      breaksw

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

    default:
      breaksw
  endsw

end
goto parse_args_return;

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

############--------------##################
check_params:
  if (! $?SUBJECTS_DIR) then
    echo "ERROR: SUBJECTS_DIR is not declared!"
    echo "  Either set the SUBJECTS_DIR environment variable,"
    echo "  or declare using --sdir argument, the root directory"
    echo "  for subject data files."
    exit 1
  endif
  if(! -e $SUBJECTS_DIR ) then
    echo "ERROR: SUBJECTS_DIR $SUBJECTS_DIR does not exist."
    exit 1;
  endif
  if(! $?FREESURFER_HOME ) then
    echo "ERROR: environment variable FREESURFER_HOME not set."
    exit 1;
  endif
  if(! -e $FREESURFER_HOME ) then
    echo "ERROR: FREESURFER_HOME $FREESURFER_HOME does not exist."
    exit 1;
  endif
  if($#average_subject == 0) then
    echo "ERROR: must spect average subject name with --out"
    exit 1
  endif
  if($#sdout == 0) set sdout = $SUBJECTS_DIR
  set outdir = $sdout/$average_subject
  if(-e $outdir && ! $Force) then
    echo "ERROR: $outdir already exists, select a new average subject name"
    echo "       or delete and rerun"
    exit 1;
  endif
  if($sdout == $SUBJECTS_DIR) set DoLink = 0;
  if($DoLink && -e $SUBJECTS_DIR/$average_subject) then
    echo "ERROR: subject $average_subject already exists in $SUBJECTS_DIR."
    echo "       Cannot create link. Select a different average subject name"
    echo "       or delete and re-run."
    exit 1;
  endif
  if(! $DoSurfaces && ! $DoVolumes) then
    echo "ERROR: you have turned off computing both surfaces and volumes"
    echo " Nothing to do!"
    exit 1;
  endif
  if($#average_subject == 0) then
    echo "ERROR: must specify the output subject name with --out"
    exit 1;
  endif
goto check_params_return;
############--------------##################

############--------------##################
usage_exit:
  echo ""
  echo "USAGE: make_average_subject"
  echo ""
  echo "Required Arguments"
  echo "   --subjects <subj1> <subj2> ... <subjN>"
  echo "             : or declare subjects in SUBJECTS env var"
  echo "   --fsgd fsgdfile : get subject list from fsgd"
  echo "   --f subjectlistfile : put all subject names in a text file"
  echo "   --out <average subject name>"
  echo ""
  echo "Optional Arguments"
  echo "   --sd-out sdout : put output under sdout instead of SUBJECTS_DIR"
  echo "   --no-link : do not link back to the original SUBJECTS_DIR with --sd-out"
  echo "   --sdir <SUBJECTS_DIR to use instead of the one in the env>"
  echo "   --sd      : same as --sdir"
  echo "   --ico <ico order> : change order of icosahedron (default=7)"
  echo "   --xform <transform_fname>   : filename of vol/coordinate transform file"
  echo "   --mni152 : set xform to synthmorph.1.0mm.1.0mm/warp.to.mni152.1.0mm.1.0mm.nii.gz"
  echo "        should be able to use warp.to.mni152.1.0mm.1.0mm.inv.nii.gz, but ..."
  echo "   --surf-reg <surface name>   : alternative registration surface"
  echo "                                 default: sphere.reg"
  echo "   --no-surf : do not make average surfaces"
  echo "   --no-vol  : do not make average volumes"
  echo "   --force   : overwrite existing average subject data"
  echo "   --keep-all-orig : concatenate all orig vols into mri/orig.all.mgz"
  echo "   --no-symlink : do not use symbolic links with surfs (just copy files)"
  echo "   --no-ribbon : do not create ribbon.mgz and aparc+aseg.mgz files"
  echo "   --no-surf2surf : use old parametric surface mapping method (may give big faces at the poles)"
  echo "   --rca-threads nthreads : number of threads to pass to recon-all"
  echo ""
  echo "   --help    : short descriptive help"
  echo "   --version : script version info"
  echo "   --echo    : enable command echo, for debug"
  echo "   --debug   : same as --echo"
  echo ""

  if(! $PrintHelp) exit 1;

  echo Version: $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

Creates average subject by averaging surfaces, curvatures, and volumes
from a set of subjects. The surface is a 7th order icosahedron
tesselation.  For surfaces, the XYZ coordinate of a vertex is computed
as the average talairach coordinate of that vertex in each subject. The
talairach coordinate is based on talairach.xfm (unless changed with
--xform), so the individual talairachs must be accurate for the final
coordinate to be meaningful. Note that even though talairach coordinates
are used for surfaces, all surface-based averaging is done using the
surface atlas (NOT talairach averaging!).

Calls make_average_surface and make_average_volume. See these programs
for specific help.

The subject list can be specified in one of three ways:
  (1) on the command-line with --subjects
  (2) through the SUBJECTS environment variable
  (3) specifying a FreeSurfer Group Descriptor (FSGD) file. The FSGD is
      used by freesurfer to specify designs for statistical analysis.
      See surfer.nmr.mgh.harvard.edu/docs/fsgdf.txt.

The output will be created in SUBJECTS_DIR/averagesubjectname unless
--topdir is specified. In this case, the data are stored in
topdir/averagesubjectname, and a link is created to
SUBJECTS_DIR/averagesubjectname. This can convenient when your
the disk that hosts your SUBJECTS_DIR starts to get full.

EXAMPLES

Example 1:

  make_average_subject --out avgsubject --subjects subj1 subj2 subj3 subj4

will create $SUBJECTS_DIR/avgsubject with average surfaces for orig,
white, pial, inflated for each hemi. It will also create average volumes
for orig, brain, and T1.  Notice that the '--out avgsubject' is merely
overriding the default output name 'average'.

Example 2:

  setenv SUBJECTS = (subj1 subj2 subj3 subj4)
  make_average_subject --out avgsubject

will do the same as Example 1.

Example 3: check that the average subject volume aligns with the
talairach subject:

  tkregisterfv --fstal --s avgsubject --mgz

Example 4: check that the average subject surfaces align with the
volume:

  tkmedit avgsubject orig.mgz lh.white

You should see that the surfaces more-or-less align with the folds.
Remember this is talairach, so the volume will be blurry.

SEE ALSO

make_average_volume, make_average_surface, recon-all, make_final_surfaces,
morph_subject

GETTING HELP

Run recon-all --help for extensive text on the reconstruction process.
Or, send email to freesurfer@nmr.mgh.harvard.edu
See also https://surfer.nmr.mgh.harvard.edu
