#!/bin/tcsh

@global_parse `basename $0` "$*" ; if ($status) exit 0

#set version   = "0.0";  set rev_dat   = "June 3, 2022"
# [PT]  creation of this script, which (at present) is a useful
#       precursor for EPI-anatomical alignment.
#
#set version   = "1.0";  set rev_dat   = "June 3, 2022"
# [PT]  add help file
#
#set version   = "1.1";  set rev_dat   = "July 4, 2022"
# [PT]  change how masking is turned off
#
set version   = "1.2";  set rev_dat   = "Jan 29, 2024"
# [PT]  change how local_mask is parsed, so '-mask DSET' is 
#       properly handled with an initial dset copy to the wdir
#
# ----------------------------------------------------------------

set abbrev = "LocalUni"

# ----------------------- set defaults --------------------------

set input     = ""
set opref     = ""
set odir      = "."

set pppp      = "`3dnewid -fun11`"
set wdir_base = "__wdir_${abbrev}"
set wdir_name = "${wdir_base}_${pppp}"

set local_perc = 50
set local_rad  = -3
set local_mask = "-automask"

set filt_thr   = 1.5

set overwrite  = ""

set DO_CLEAN  = 1                       # default: keep working dir

# ------------------- process options, a la rr ----------------------

if ( $#argv == 0 ) goto SHOW_HELP

set ac = 1
while ( $ac <= $#argv )
    # terminal options
    if ( ("$argv[$ac]" == "-h" ) || ("$argv[$ac]" == "-help" )) then
        goto SHOW_HELP
    endif
    if ( "$argv[$ac]" == "-ver" ) then
        goto SHOW_VERSION
    endif

    if ( "$argv[$ac]" == "-echo" ) then
        set echo

    # ----------- required
    else if ( "$argv[$ac]" == "-input" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set input = "$argv[$ac]"

    else if ( "$argv[$ac]" == "-prefix" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set opref = `basename "$argv[$ac]"`
        set odir  = `dirname  "$argv[$ac]"`

    # ----------- 3dLocalStat opts

    else if ( "$argv[$ac]" == "-local_perc" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set local_perc = "$argv[$ac]"

    else if ( "$argv[$ac]" == "-local_rad" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set local_rad = "$argv[$ac]"

    else if ( "$argv[$ac]" == "-local_mask" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set local_mask = "$argv[$ac]"
        # special case to turn off masking
        if ( "${local_mask}" == "None" ) then
            set local_mask = ""
        endif

    else if ( "$argv[$ac]" == "-wdir_name" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set wdir_name = "$argv[$ac]"

        set check     = `echo "${wdir_name}" | grep '/'`
        if ( "${check}" != "" ) then
            echo "\n\n** ERROR: -wdir_name arg must not have '/':"
            echo "   '${wdir_name}'\n\n"
            goto BAD_EXIT
        endif

    else if ( "$argv[$ac]" == "-filter_thr" ) then
        if ( $ac >= $#argv ) goto FAIL_MISSING_ARG
        @ ac += 1
        set filt_thr = "$argv[$ac]"

    else if ( "$argv[$ac]" == "-overwrite" ) then
        set overwrite = "-overwrite"

    else if ( "$argv[$ac]" == "-no_clean" ) then
        set DO_CLEAN = 0
        
    else
        echo "\n\n** ERROR: unexpected option #$ac = '$argv[$ac]'\n\n"
        goto BAD_EXIT
        
    endif
    @ ac += 1
end

# =======================================================================
# ============================ ** SETUP ** ==============================
# =======================================================================

if ( "${input}" == "" ) then
    echo "** ERROR: missing input file. Use '-input ..'"
    goto BAD_EXIT
endif

if ( "${opref}" == "" ) then
    echo "** ERROR: missing output prefix. Use '-prefix ..'"
    goto BAD_EXIT
endif

# ===================== output dir + wdir =======================
 
echo "++ Start 3dLocalUnifize work"

# check output directory, use input one if nothing given

if ( ! -e "${odir}" ) then
    echo "++ Making new output directory: ${odir}"
    \mkdir -p "${odir}"
endif

set wdir = "${odir}/${wdir_name}"

# make the working directory
if ( ! -e "${wdir}" ) then
    echo "++ Making working directory: ${wdir}"
    \mkdir -p "${wdir}"
else
    echo "+* WARNING: Somehow found a premade working directory (?):"
    echo "      ${wdir}"
endif

# check about whether local_mask opt uses a mask dset; if so, copy
# that mask to wdir and change var to use that local copy
set nlm = `python -c "print(len('${local_mask}'.split()))"`
if ( "${nlm}" == "2" ) then
    # does local_mask start with '-mask'?
    set lll = `echo "${local_mask}" | awk '{print $1}'`
    if ( "${lll}" == "-mask" ) then
        # if here, we have a mask dset input

        # get name of mask; careful of subbrick selectors
        set mmm = `echo "${local_mask}" | awk '{print $2}'`

        # copy the dset
        3dTcat ${overwrite}                                         \
            -prefix   "${wdir}/dset_mask.nii.gz"                    \
            "${mmm}"

        if ( $status ) then
            echo "** ERROR when processing local_mask opt: '${local_mask}'"
            goto BAD_EXIT
        endif
            
        # edit the local_mask opt to use the local wdir mask name
        set local_mask = "-mask dset_mask.nii.gz"
    endif
endif


# ======================= main program work ===========================

# Copy original image in

set idset    = "${input}"
set odset_cp = dset_00_cp.nii.gz

3dTcat ${overwrite}                                                 \
    -prefix   "${wdir}/${odset_cp}"                                 \
    "${idset}"

cd "${wdir}"

# Calc the smooth/median image

set idset    = "${odset_cp}"
set odset_lu = dset_01_lu.nii.gz

3dLocalstat ${overwrite}                                            \
    ${local_mask}                                                   \
    -nbhd     "SPHERE(${local_rad})"                                \
    -stat     "perc:${local_perc}:${local_perc}:1"                  \
    -prefix   "${odset_lu}"                                         \
    "${idset}"

# Calc the ratio of original to this

set idset     = "${odset_lu}"
set jdset     = "${odset_cp}"
set odset_rat = dset_02_rat.nii.gz

3dcalc ${overwrite}                                                \
    -a       "${idset}"                                            \
    -b       "${jdset}"                                            \
    -expr    "b/a"                                                 \
    -prefix  "${odset_rat}"

set dset_out = "${odset_rat}"

# (opt) Filter possible outlier ratio values

if ( `echo "${filt_thr} > 0 " | bc` ) then
    echo "++ Apply filter threshold to scaled image: ${filt_thr}"

    set idset      = "${odset_rat}"
    set odset_filt = dset_03_filt.nii.gz

    3dcalc ${overwrite}                                            \
        -a       "${idset}"                                        \
        -expr    "maxbelow(${filt_thr},a)"                         \
        -prefix  "${odset_filt}"

    set dset_out = "${odset_filt}"
else
    echo "++ NO filter threshold will be applied to the scaled image"

endif

# ----------- finish

3dcopy ${overwrite}                                               \
    "${dset_out}"                                                 \
    "../${opref}"

# ------------------------- wrap up ----------------------------

# move out of wdir to the odir
cd ..
set whereout = "$PWD"

if ( "$DO_CLEAN" == "1" ) then
    echo "\n+* Removing the working dir: '${wdir_name}'\n"
    \rm -rf "${wdir_name}"
else
    echo "\n++ NOT removing the working dir: '${wdir_name}'\n"
endif

echo ""
echo "++ DONE! View the finished, locally-unifized product:"
echo "     ${whereout}/${opref}"
echo ""


goto GOOD_EXIT

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

SHOW_HELP:
cat << EOF
-------------------------------------------------------------------------

OVERVIEW ~1~

This program takes an input and generates a simple "unifized" output
volume.  It estimates the median in the local neighborhood of each
voxel, and uses that to scale each voxel's brightness.  The result is
a new dataset of brightness of order 1, which still has the
interesting structure(s) present in the original.

This program's output looks very useful to help with dataset alignment
(esp. EPI-to-anatomical) in a wide array of cases.

ver   : ${version}
date  : ${rev_dat}
auth  : PA Taylor (SSCC, NIMH, NIH)


USAGE ~1~

This program is generally run as:

    3dLocalUnifize [options] -prefix DSET_OUT -input DSET_IN

where the following options exist:

  -input     DSET_IN  :(req) input dataset
  
  -prefix   DSET_OUT  :(req) output dataset name, including path

  -wdir_name WD       :name of temporary working directory, which 
                       should not contain any path information---it will be
                       created in the same directory as the final dataset
                       is created
                       (def: ${wdir_base}_, plus a random alphanumeric str)

  -echo               :run this program very verbosely (def: don't do so)

  -no_clean           :do not remove the working directory (def: remove it)

 ... and the following are 'tinkering' options, likely not needed in
     most cases:

  -local_rad LR       :the spherical neighborhood's radius for the 
                       3dLocalStat step (def: ${local_rad})

  -local_perc LP      :the percentile used in the 3dLocalStat step,
                       generating the scaling volume 
                       (def: ${local_perc})

  -local_mask LM      :provide the masking option to be used in the
                       3dLocalStat step, which should be enclosed in
                       quotes for passing along to the internal
                       program call.  So, to use a pre-existing mask,
                       you might call this option like:
                         -local_mask "-mask my_mask.nii.gz"
                       To remove any masking, put the special keyword
                       "None" as the option value.
                       (def: "${local_mask}")

  -filter_thr FT      :put a ceiling on values in the final, scaled dataset,
                       whose values should be of order 1; setting FT to be a
                       value <=0 turns off this final filtering
                       (def: ${filt_thr})


NOTES ~1~

  This program is designed to not need a lot of tinkering with
  options, such as the '-local_* ..' ones.  In most cases, the default
  scaling will be useful.


EXAMPLES ~1~

  1. Basic local unifizing:
     3dLocalUnifize                                                  \\
        -prefix  vr_base_LU                                          \\
        -input   vr_base_min_outlier+orig.HEAD

  1. Same as above, without masking:
     3dLocalUnifize                                                  \\
        -prefix      vr_base_LU_FOV                                  \\
        -input       vr_base_min_outlier+orig.HEAD                   \\
        -local_mask  None

EOF

# ----------------------------------------------------------------------

    goto GOOD_EXIT

SHOW_VERSION:
   echo "version  $version (${rev_dat})"
   goto GOOD_EXIT

FAIL_MISSING_ARG:
    echo "** ERROR! Missing an argument after option flag: '$argv[$ac]'"
    goto BAD_EXIT

BAD_EXIT:
    exit 1

GOOD_EXIT:
    exit 0
