#! /bin/ksh

set -x

# ----------------------------------------------------------------------
# Utility functions

function fail {
    exitmsg="$1"

    set +x
    echo " "
    echo "!!! ERROR in hwrf_realtime_tracker.sh:"
    for line in "$@" ; do
        echo "!!! $line"
    done
    if [[ ! -z "${PDY:-}" && ! -z "${CYL:-}" ]] ; then
        echo "!!! model= ${atcfout:-hwrf}, forecast initial time = $PDY$CYL"
    fi
    echo " "
    set -x

    "${utilscript:-${NWPROD}/util/ush}/setup.sh"
    ./err_exit "$exitmsg"
    exit 1
}

function wait_for {
    # Wat up to $1 seconds for a file, checking for $2 seconds in
    # between using hwrf_file_complete.pl.  Run check_sig after 
    # each hwrf_file_complete.pl check.
    set -x
    the_maxwait="$1"
    the_waitstep="$2"
    shift 2
    the_now=$( date +%s )
    the_giveup=$(( the_now + the_maxwait - the_waitstep ))

    # We only need to call check_sig on CCS in non-NCO mode,
    # since other systems do not preempt.  
    "$USHhwrf/hwrf_file_complete.pl" -w "$the_maxwait" \
        -C $*
}

function tempify {
    echo $( dirname "$1" )/temp.$( basename "$1" )."$2"
}

function copyit {
    set -x
    junkstr=$$.$RANDOM.$( hostname )
    if [[ "$1" == '-6' ]] ; then
        # $1 = atcfunix file, $2 = destination, keep only 6hourly times
        thetemp=$( tempify "$2" "$junkstr" )
        cat "$2" | awk '{if(($6+0)%6 == 0) { print $0}}' > "$thetemp"
        $USHhwrf/hwrf_cleanup_track.sh "$thetemp" "$thetemp.clean"
        mv -f "$thetemp.clean" "$3"
    elif [[ "$1" == '-all' ]] ; then
        # $1 = atcfunix file, $2 = destination, keep all times
        thetemp=$( tempify "$2" "$junkstr" )
        $USHhwrf/hwrf_cleanup_track.sh "$2" "$thetemp.clean"
        mv -f "$thetemp.clean" "$3"
    elif [[ "$1" == '-rad6' ]] ; then
        # $1 = atcfunix file, $2 = radii file, $3 = destination, keep only 6hourly times
        thetemp=$( tempify "$2" "$junkstr" )
        cat "$2" | awk '{if((0+substr($1,15,3))%12 == 0) { print $0 }}' \
            > "$thetemp"
        $USHhwrf/hwrf_cleanup_track.sh "$1" -no-out \
            "$thetemp" "$thetemp.clean"
        mv -f "$thetemp.clean" "$3"
    else
        # Create $2 from $1 in an atomic operation by copying $1 to a
        # temporary file and moving the file to $2
        thetemp=$( tempify "$2" "$junkstr" )
        cp "$1" "$thetemp"
        mv -f "$thetemp" "$2"
    fi
}

function usage {
    cat<<EOF 1>&2
ERROR: Syntax:
    hwrf_realtime_tracker.sh mode source YMDH storm stormid \\
        /path/to/vitdat path/to/comdir/ \\
        /path/to/tracker/grib/dir/ \\
        /path/to/tracker/tracking/dir/ \\
        [ fhours ]

    Will prepare tracker GRIB files and run the tracker.

Enviromental variables:

    \$USHhwrf -- path to HWRF ush/ directory
    \$EXEChwrf -- path to HWRF exec/ directory
    \$PARMhwrf -- path to HWRF parm/ directory
    \$ATMOS_DOMAINS -- number of atmospheric domains used to run
        this HWRF model.  Default: 3

Parameters:

    mode -- "make_grib", "track", "deliver" or "all"
        make_grib -- job will make GRIB files based on post-processor
            output, as it becomes available.
        track -- job will run the tracker, waiting for GRIB files from
            the make_grib job before processing each forecast hour
        deliver -- job will deliver tracker output
        all -- job does everything, without running in parallel with
            the forecast
    source -- which GRIB files to use when making 20x20 degree files:
        "27:9:3" -- gets data from hwrfprs_p and hwrfprs_m
        "27:9" -- gets data from hwrfprs_p and hwrfprs_n
        "27" -- gets data from hwrfprs_p but centers on hwrfprs_n
    YMDH -- date and time as a ten-digit number (YYYYMMDDHH)
    storm -- storm name (Irene, Katrina, etc.), not case-sensitive
    stormid -- storm number and basin (ie.: 13L)
    /path/to/vitdat/ -- path to tcvitals data
    /path/to/comdir/ -- path to com directory
    /path/to/tracker/grib/dir/ -- path to the directory that will 
        contain tracker input grib files (work area for make_grib job)
    /path/to/tracker/track/dir/ -- path to the working directory for
        the tracker program (work area for track job)
    /path/to/wrf/dir/ -- path to the parent of the PARENT, NEST and
        DOM12 directories, which contain WRF GRIB files

    [ fhours ] -- Optional.  List of forecast hours.
        Default: 0, 3, 6, 9, ... 126
EOF
    fail "SCRIPT hwrf_realtime_tracker.sh WAS CALLED INCORRECTLY -- NOW ABORTING" "$*"
}

# ----------------------------------------------------------------------
# Parse argument list

if [[ "$#" -lt 10 ]] ; then
    usage TOO FEW ARGUMENTS: AT LEAST 10 REQUIRED
fi
if [[ -z "${USHhwrf:-}" ]] ; then
    usage "YOU MUST SPECIFY ENVIRONMENT VARIABLE USHhwrf"
fi
if [[ -z "${EXEChwrf:-}" ]] ; then
    usage "YOU MUST SPECIFY ENVIRONMENT VARIABLE EXEChwrf"
fi
if [[ -z "${PARMhwrf:-}" ]] ; then
    usage "YOU MUST SPECIFY ENVIRONMENT VARIABLE PARMhwrf"
fi

mode="$1"
source="$2"
YMDH="$3"
storm=$( echo "$4" | tr A-Z a-z )
stormid=$( echo "$5" | tr A-Z a-z )
vit="$6"
COMOUT="$7"
gribwork="$8"
trakwork="$9"
wrfdir="${10}"

shift 10

fcsthrs="$*"

if [[ "$PARAFLAG" == YES ]] ; then
    # Value of tracker's wait_max_wait parameter, which
    # specifies the maximum amount of time to wait for
    # the input grib file.  Also used by the grib
    # generator job as the max. time to wait for the
    # post output grib file
    wait_max_wait=7200  # wait longer in para mode since jobs may run in wrong order
else
    wait_max_wait=1800
fi

if [[ -z "$fcsthrs" ]] ; then
    fcsthrs=$( seq 0 3 126 )
fi

if [[ "$mode" != make_grib && "$mode" != track && "$mode" != deliver && "$mode" != all ]] ; then
    fail "Invalid value for mode in hwrf_realtime_tracker.sh"
fi

atcfout=hwrf  # don't change
cmodel=hwrf   # don't change
PDY=$( echo "$YMDH" | cut -c1-8 )
CYL=$( echo "$YMDH" | cut -c9-10 )
stormenv="$storm$stormid"
syy=`echo ${PDY} | cut -c3-4`
smm=`echo ${PDY} | cut -c5-6`
sdd=`echo ${PDY} | cut -c7-8`
shh=${CYL}
symd=`echo ${PDY} | cut -c3-8`
syyyy=`echo ${PDY} | cut -c1-4`

nidymdh="$COMOUT/$storm$stormid.$YMDH"

ATMOS_DOMAINS="${ATMOS_DOMAINS:-3}"

if [[ ! ( "$ATMOS_DOMAINS" -eq 2 || "$ATMOS_DOMAINS" -eq 3 ) ]] ; then
    usage "IF SPECIFIED, ATMOS_DOMAINS MUST BE 2 OR 3 IN hwrf_realtime_tracker.sh"
fi

# Only needed for operational runs:
export gltrkdir=${gltrkdir:-/com/hur/${envir}/global}
TRKBASE=${TRKBASE:-$trakwork}

# ----------------------------------------------------------------------
# Turn on/off various features here

phaseflag=n
structflag=n
ikeflag=n
write_vit=y
use_waitfor=y
contour_interval=100.0
atcfnum=81
mslpthresh=0.0015
v850thresh=1.5000
if [[ "$mode" == all ]] ; then
    use_waitfor=n
fi

# ----------------------------------------------------------------------
# Paths to executables

wgrib="${WGRIB_PATH:-${utilexec:-${NWPROD}/util/exec}/wgrib}"
cgb="${COPYGB_PATH:-${utilexec:-${NWPROD}/util/exec}/copygb}"
grb2ctl=${USHhwrf}/hwrf_grib2ctl.pl
gix="${GRIBINDEX_PATH:-${utilexec:-${NWPROD}/util/exec}/grbindex}"
gettrk="${GETTRK_PATH:-${EXEChwrf:-${NWPROD}/hwrf.${HWRF_VERSION}/exec}/hwrf_unified_tracker}"
vint="${VINT_PATH:-${EXEChwrf:-${NWPROD}/exec}/hwrf.${HWRF_VERSION}/hwrf_vint}"
tave="${TAVE_PATH:-${EXEChwrf:-${NWPROD}/exec}/hwrf.${HWRF_VERSION}/hwrf_tave}"

wgrib_parmlist=" HGT:925 HGT:850 HGT:700 UGRD:850 UGRD:700 UGRD:500 VGRD:850 VGRD:700 VGRD:500 SurfaceU SurfaceV ABSV:850 ABSV:700 PRMSL HGT:900 HGT:800 HGT:750 HGT:650 HGT:600 HGT:550 HGT:500 HGT:450 HGT:400 HGT:350 HGT:300 HGT:250 TMP:500 TMP:450 TMP:400 TMP:350 TMP:300 TMP:250"

# ----------------------------------------------------------------------
# Try to find gribmap.  This code was stolen from hwrf_post_process.sh:

grbmap=/usrx/local/grads/bin/gribmap  # path hard-coded in operational HWRF
if [[ "$PARAFLAG" == YES ]] ; then
    # override NCO's hard-coded path
    grbmap=$( /usr/bin/which gribmap )
    if [[ -z "$grbmap" || ! -x "$grbmap" ]] ; then
        echo WARNING: gribmap is not in your path.  I will check some default locations.
        grbmap=/bin/false

        # Vapor: /usrx/local/grads/bin/gribmap
        # CCS:   /usrx/local/grads/bin/gribmap
        # Jet:   /opt/grads/2.0.a2/bin/gribmap
      
        for find_grbmap in  /usrx/local/grads/bin/gribmap /opt/grads/2.0.a2/bin/gribmap MISSING ; do
            if [[ -x "$find_grbmap" ]] ; then 
                break
            fi
        done
        
        if [[ "$find_grbmap" == MISSING ]] ; then
            echo "WARNING: I cannot find gribmap, so the grads input files *.ctl and *.idx will not be produced."
            echo "         That will not affect the operational system, but you will have to produce the "
            echo "         grads input files yourself if you want them."
            grbmap=gribmap # provide no path, and hope for the best
        else
            grbmap="$find_grbmap"
        fi
    fi
fi

# ----------------------------------------------------------------------
# Dump some variables for NCO's sake

set +x
echo " "
echo " #--------------------------------------------------------------------#"
echo " At beginning of tracker script, the following variables are defined:"
echo "   PDY ................................... $PDY"
echo "   CYL ................................... $CYL"
echo "   cmodel ................................ hwrf"
echo "   mode .................................. $mode"
echo "   source ................................ $source"
echo "   YMDH .................................. $YMDH"
echo "   storm ................................. $storm"
echo "   stormid ............................... $stormid"
echo "   vit ................................... $vit"
echo "   COMOUT ................................ $COMOUT"
echo "   gribwork .............................. $gribwork"
echo "   trakwork .............................. $trakwork"
echo "   jobid ................................. $jobid"
echo "   envir ................................. $envir"
echo "   gltrkdir .............................. $gltrkdir"
echo "   SENDCOM ............................... $SENDCOM"
echo "   SENDDBN ............................... $SENDDBN"
echo " "
set -x

# For HWRF, we will combine the 27km and either 9km or combined 9:3 km
# files into a single 20x20 degree, 0.03 degree resolution lat-lon
# grid file that follows the inner nest.
if [[ "$mode" == make_grib || "$mode" == all ]] ; then
    
    if [[ ! -d "$gribwork" ]] ; then
        "$USHhwrf"/hwrf_mkdirp.sh "$gribwork"
    fi
    
    cd "$gribwork"
    if [[ "$?" != 0 ]] ; then
        fail "Cannot cd into \"$gribwork\" directory"
    fi

    "${utilscript:-${NWPROD}/util/ush}/setup.sh"

    if [ -s ${gribwork}/hwrf.${stormenv}.pgrb.${PDY}${CYL} ]; then
        rm ${gribwork}/hwrf.${stormenv}.pgrb.${PDY}${CYL}
    fi

    gribpre=$( echo "$storm$stormid.$YMDH" | tr a-z A-Z )      

    for raw_fhour in $fcsthrs ; do
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        fhour=$( printf "%02d" $( echo "$raw_fhour" | awk '{print 0+$1}' ) )

#     First do a wgrib to parse out only the variables we need.  This will make
#     the subsequent copygb procedure go much faster.  First we will parse out
#     the necessary variables from the original 0.25 ("p25") files, which cover
#     the full domain.

        true > ${gribwork}/hwrf_p25_orig_parsed.${stormenv}.${PDY}${CYL}.f${fhour}

        #hwrf_p25_orig=${COMOUT}/${stormenv}.${PDY}${CYL}.hwrfprs_p.grbf${fhour}
        hwrf_p25_orig=$wrfdir/PARENT/$gribpre.parent_grbf$fhour

        if ( ! wait_for "$wait_max_wait" 60 -v -o 15 -s 1 \
                   -S 15 "$hwrf_p25_orig" ) ; then
            fail "INPUT FILE MISSING - TRACKER IS ABORTING DUE TO MISSING ${fhour}hr FORECAST PARENT GRIB FILE IN COM DIRECTORY"
        fi

        $wgrib -s ${hwrf_p25_orig} >hwrf_p25_orig.ix

        for parm in ${wgrib_parmlist}
        do
            case ${parm} in
                "SurfaceU") parm="UGRD:10 m " ;;
                "SurfaceV") parm="VGRD:10 m " ;;
                *) true ;;
            esac
            if [[ "$PARAFLAG" == YES ]] ; then
                $USHhwrf/hwrf_port_checksig.sh
            fi
            grep "${parm}" hwrf_p25_orig.ix | $wgrib -s ${hwrf_p25_orig} -i -grib -append \
                -o ${gribwork}/hwrf_p25_orig_parsed.${stormenv}.${PDY}${CYL}.f${fhour}
        done


#     Now we will parse out the necessary variables from the original
#     files, which cover only the innermost mesh, and are on the e-grid.

        true > ${gribwork}/hwrf_egrd_orig_parsed.${stormenv}.${PDY}${CYL}.f${fhour}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        if [[ "$source" == 27:9 || "$source" == 27 ]] ; then
            #hwrf_egrd_orig=${COMOUT}/${stormenv}.${PDY}${CYL}.hwrfprs_n.grbf${fhour}
            hwrf_egrd_orig=$wrfdir/NEST/HWRF_NEST.GrbF$fhour
            if ( ! wait_for 3600 60  -v -o 15 -s 1 -S 15 "$hwrf_egrd_orig" ) ; then
                fail "INPUT FILE MISSING - TRACKER IS ABORTING DUE TO MISSING ${fhour}hr FORECAST 9KM RES. GRIB FILE IN COM DIRECTORY"
            fi
        elif [[ "$source" == 27:9:3 ]] ; then
            #hwrf_egrd_orig=${COMOUT}/${stormenv}.${PDY}${CYL}.hwrfprs_m.grbf${fhour}
            hwrf_egrd_orig=$wrfdir/COMBINE/HWRF_MOVE.GrbF$fhour
            if ( ! wait_for 3600 60  -v -o 15 -s 1 -S 15 "$hwrf_egrd_orig" ) ; then
                fail "INPUT FILE MISSING - TRACKER IS ABORTING DUE TO MISSING ${fhour}hr FORECAST COMBINED 9:3KM RES. GRIB FILE IN COM DIRECTORY"
            fi
        fi
        $wgrib -s ${hwrf_egrd_orig} >hwrf_egrd_orig.ix

        for parm in ${wgrib_parmlist}
        do
            case ${parm} in
                "SurfaceU") parm="UGRD:10 m " ;;
                "SurfaceV") parm="VGRD:10 m " ;;
                *) true ;;
            esac
            if [[ "$PARAFLAG" == YES ]] ; then
                $USHhwrf/hwrf_port_checksig.sh
            fi
            grep "$parm" hwrf_egrd_orig.ix | $wgrib -s ${hwrf_egrd_orig} -i -grib -append \
                        -o ${gribwork}/hwrf_egrd_orig_parsed.${stormenv}.${PDY}${CYL}.f${fhour}
        done 

        hwrf_p25=${gribwork}/hwrf_p25_orig_parsed.${stormenv}.${PDY}${CYL}.f${fhour}
        hwrf_egrd=${gribwork}/hwrf_egrd_orig_parsed.${stormenv}.${PDY}${CYL}.f${fhour}

        hwrf_merge_basic=${gribwork}/hwrf.merge_basic.${stormenv}.${PDY}${CYL}.f${fhour}

        if [[ "$source" == 27:9 || "$source" == 27 ]] ; then
            origwestlon=`${wgrib} -V ${hwrf_egrd} | grep long | head -1 | awk '{printf ("%d",$2*1000)}'`
            origeastlon=`${wgrib} -V ${hwrf_egrd} | grep long | head -1 | awk '{printf ("%d",$4*1000)}'`
            let newwestlon=origwestlon-2500
            let neweastlon=origeastlon+2500
            
            origsolat=`${wgrib} -V ${hwrf_egrd} | grep latlon | head -1 | awk '{printf ("%d",$5*1000)}'`
            orignolat=`${wgrib} -V ${hwrf_egrd} | grep latlon | head -1 | awk '{printf ("%d",$3*1000)}'`
            let newsolat=origsolat-4000
            let newnolat=orignolat+4000

            grid="255 0 400 400 ${newnolat} ${newwestlon} 128 ${newsolat} ${neweastlon} 050  050 0"
        elif [[ "$source" == 27:9:3 ]] ; then
            origwestlon=`${wgrib} -V ${hwrf_egrd} | grep long | head -1 | awk '{printf ("%d",$2*1000)}'`
            origeastlon=`${wgrib} -V ${hwrf_egrd} | grep long | head -1 | awk '{printf ("%d",$4*1000)}'`
            let newwestlon=origwestlon-2500
            let neweastlon=origeastlon+2500
            
            origsolat=`${wgrib} -V ${hwrf_egrd} | grep latlon | head -1 | awk '{printf ("%d",$5*1000)}'`
            orignolat=`${wgrib} -V ${hwrf_egrd} | grep latlon | head -1 | awk '{printf ("%d",$3*1000)}'`
            let newsolat=origsolat-4000
            let newnolat=orignolat+4000

            grid="255 0 668 668 ${newnolat} ${newwestlon} 128 ${newsolat} ${neweastlon} 030  030 0"
        fi

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        if [ ! -s ${hwrf_p25} -o ! -s ${hwrf_egrd} ]
        then
            set +x
            echo " "
            echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
            echo " !!! AT LEAST ONE OF THESE 2 HWRF FILES IS MISSING AT HOUR fhour= ${fhour}"
            echo " !!!    ${hwrf_p25}"
            echo " !!!    ${hwrf_egrd}"
            echo " !!! THIS COULD BE AN ERROR, OR IT COULD BE THAT THE MODEL ITSELF STOPPED"
            echo " !!! PRIOR TO 126h DUE TO THE STORM REACHING THE GRID BOUNDARY."
            echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
            set -x
            continue
        fi

        if [[ "$source" == 27 ]] ; then
            cp -pf "$hwrf_p25" "$hwrf_merge_basic"
        else
            $cgb -xg"$grid" -M ${hwrf_p25} ${hwrf_egrd} ${hwrf_merge_basic}
        fi

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        if [ -s ${hwrf_merge_basic}.i ]; then rm ${hwrf_merge_basic}.i; fi

        $gix ${hwrf_merge_basic} ${hwrf_merge_basic}.i
        x1=${hwrf_merge_basic}.i

        set +x
        echo " "
        echo "TIMING: Date in interpolation for fhour= $fhour before = `date`"
        echo " "
        set -x

#      catfile=${gribwork}/${cmodel}_cat.${PDY}${CYL}.f${fhour}
#      >${catfile}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        gfile=${hwrf_merge_basic}
        ifile=${x1}

        gparm=7
        namelist=${gribwork}/vint_input.${PDY}${CYL}.z
        echo "&timein ifcsthour=${fhour}, iparm=${gparm}/"  >${namelist}

        ln -s -f ${gfile}                                   fort.11
        ln -s -f $PARMhwrf/hwrf_hgt_levs.txt                fort.16
        ln -s -f ${ifile}                                   fort.31
        ln -s -f ${gribwork}/${cmodel}.${PDY}${CYL}.z.f${fhour} fort.51

        $vint <${namelist}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        gparm=11
        namelist=${gribwork}/vint_input.${PDY}${CYL}
        echo "&timein ifcsthour=${fhour}, iparm=${gparm}/"  >${namelist}

        ln -s -f ${gfile}                                   fort.11
        ln -s -f $PARMhwrf/hwrf_tmp_levs.txt                fort.16
        ln -s -f ${ifile}                                   fort.31
        ln -s -f ${gribwork}/${cmodel}.${PDY}${CYL}.t.f${fhour} fort.51

        $vint <${namelist}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        namelist=${gribwork}/tave_input.${PDY}${CYL}
        echo "&timein ifcsthour=${fhour}, iparm=${gparm}/"   >${namelist}
#      echo "        lt_units='${lead_time_units}'/"       >>${namelist}

        ffile=${gribwork}/${cmodel}.${PDY}${CYL}.t.f${fhour}
        ifile=${gribwork}/${cmodel}.${PDY}${CYL}.t.f${fhour}.i
        $gix ${ffile} ${ifile}

        ln -s -f ${ffile}                                      fort.11
        ln -s -f ${ifile}                                      fort.31
        ln -s -f ${gribwork}/${cmodel}_tave.${PDY}${CYL}.f${fhour} fort.51

        $tave <${namelist}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        tavefile=${gribwork}/${cmodel}_tave.${PDY}${CYL}.f${fhour}
        zfile=${gribwork}/${cmodel}.${PDY}${CYL}.z.f${fhour}
#      cat ${zfile} ${tavefile} >>${catfile}

#      g2=${catfile}
#      x2=${catfile}.i
#      $gix $g2 $x2

        g2=${zfile}
        x2=${zfile}.i
        $gix $g2 $x2

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        g3=${tavefile}
        x3=${tavefile}.i
        $gix $g3 $x3

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        set +x
        echo " "
        echo " Extracting HWRF GRIB data for forecast hour = $fhour"
        echo " "
        set -x

        g1=${hwrf_merge_basic}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1 33 100 850' $g1 $x1 ${gribwork}/hwrfu850.grb.f${fhour};   rcc1=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1 33 100 700' $g1 $x1 ${gribwork}/hwrfu700.grb.f${fhour};   rcc2=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1 33 100 500' $g1 $x1 ${gribwork}/hwrfu500.grb.f${fhour};   rcc3=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1 33 105  10' $g1 $x1 ${gribwork}/hwrfu10m.grb.f${fhour};   rcc4=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1  7 100 850' $g1 $x1 ${gribwork}/hwrfz850.grb.f${fhour};   rcc7=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1  7 100 700' $g1 $x1 ${gribwork}/hwrfz700.grb.f${fhour};   rcc8=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid" -k'4*-1  2 102   0' $g1 $x1 ${gribwork}/hwrfmslp.grb.f${fhour};   rcc9=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid"                     $g2 $x2 ${gribwork}/hwrfphase.grb.f${fhour};  rcc10=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $cgb -g"$grid"                     $g3 $x3 ${gribwork}/hwrftave.grb.f${fhour};  rcc11=$?
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi

        if [ $rcc1 -eq 134 -o $rcc2 -eq 134 -o $rcc3 -eq 134 -o $rcc4 -eq 134 -o \
            $rcc7 -eq 134 -o $rcc8 -eq 134 -o $rcc9 -eq 134 -o $rcc10 -eq 134 -o \
            $rcc11 -eq 134 ]
        then
            set +x
            echo " "
            echo "!!! ERROR using $cgb to interpolate hwrf data.  We will stop execution because"
            echo "!!! some variables may have been copied okay, while some obviously have not, "
            echo "!!! and that could lead to unreliable results from the tracker.  Check to make"
            echo "!!! sure you've allocated enough memory for this job.  Exiting...."
            echo " "
            set -x
            fail " FAILED ${jobid} - ERROR INTERPOLATING HWRF gribwork IN TRACKER SCRIPT - ABNORMAL EXIT"
        fi

        let fmin=fhour*60
        minstr=$( echo $fmin | awk '{printf ("%05d",$1)}' )
        hwrf_20x20=${gribwork}/hwrftrk.grbf${minstr}

        cat ${gribwork}/hwrfu850.grb.f${fhour} ${gribwork}/hwrfu700.grb.f${fhour} \
            ${gribwork}/hwrfu500.grb.f${fhour} ${gribwork}/hwrfz850.grb.f${fhour} \
            ${gribwork}/hwrfz700.grb.f${fhour} ${gribwork}/hwrfmslp.grb.f${fhour} \
            ${gribwork}/hwrfu10m.grb.f${fhour} ${gribwork}/hwrfphase.grb.f${fhour} \
            ${gribwork}/hwrftave.grb.f${fhour} >${hwrf_20x20}

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        $gix ${hwrf_20x20} ${hwrf_20x20}.ix

        fhour00=$( printf '%02d' "$fhour" )

        cp ${hwrf_20x20}    $nidymdh.hwrftrk.grbf$fhour00
        cp ${hwrf_20x20}.ix $nidymdh.hwrftrk.grbf$fhour00.ix

        if [[ "$PARAFLAG" == YES ]] ; then
            # In PARA mode, also make some grads input files
            $grb2ctl -verf $nidymdh.hwrftrk.grbf$fhour00 \
                > $nidymdh.hwrftrk.grbf$fhour00.ctl
            # gribmap takes >15 seconds, so it is disabled
            # $grbmap -i $nidymdh.hwrftrk.grbf$fhour00.ctl
        fi

        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
    done

fi

if [[ "$mode" == all || "$mode" == track ]] ; then

    if [[ ! -d "$trakwork" ]] ; then
        "$USHhwrf"/hwrf_mkdirp.sh "$gribwork"
    fi
    
    cd "$trakwork"
    if [[ "$?" != 0 ]] ; then
        fail "Cannot cd into \"$gribwork\" directory"
    fi

    "${utilscript:-${NWPROD}/util/ush}/setup.sh"

    true > NULL_USING_MULTI_OPTION

    gribfile=NULL_USING_MULTI_OPTION
    ixfile=NULL_USING_MULTI_OPTION

    # Generate list of tracker output times (in minutes), and link to
    # grib input files (which may not exist yet).
    i=1
    for fhour in $fcsthrs ; do 
        if [[ "$PARAFLAG" == YES ]] ; then
            $USHhwrf/hwrf_port_checksig.sh
        fi
        let fmin=fhour*60
        minstr=$( printf "%5.5d" "$fmin" )
        printf "%4d %5d\n" "$i" "$fmin"
        ln -fs "$gribwork/hwrftrk.grbf${minstr}"    \
               hwrf.20x20.$storm$stormid.$YMDH.f"$minstr"    > /dev/null
        ln -fs "$gribwork/hwrftrk.grbf${minstr}".ix \
               hwrf.20x20.$storm$stormid.$YMDH.f"$minstr".ix > /dev/null
        let i=i+1
    done > fort.15

    export TRAK_PREFIX="${trakwork}/out.${atcfout}."
    export TRAK_SUFFIX=".${stormenv}.${PDY}${CYL}"
    export PART_PREFIX="${trakwork}/part.${atcfout}."
    export PART_SUFFIX=".${stormenv}.${PDY}${CYL}"

    if [[ "$ATMOS_DOMAINS" == 3 && "$source" == 27:9 ]] ; then
        export TRACK_12HR="$COMOUT/$stormid.trak.hwrf.atcfunix.$YMDH.dom12"
        export TRACK_PART="$COMOUT/$stormid.trak.hwrf.atcfunix.$YMDH.partial.dom12"
    elif [[ "$source" == 27 ]] ; then
        export TRACK_12HR="$COMOUT/$stormid.trak.hwrf.atcfunix.$YMDH.parent"
        export TRACK_PART="$COMOUT/$stormid.trak.hwrf.atcfunix.$YMDH.partial.parent"
    else
        export TRACK_12HR="$COMOUT/$stormid.trak.hwrf.atcfunix.$YMDH.combine"
        export TRACK_PART="$COMOUT/$stormid.trak.hwrf.atcfunix.$YMDH.partial.combine"
    fi

    ln -sf "$USHhwrf/hwrf_rttrk_partial.sh" deliver

    namelist=input.${atcfout}.${PDY}${CYL}
    cat<<EOF > $namelist
&datein inp%bcc=$( echo $YMDH | cut -c1-2 ),
        inp%byy=$( echo $YMDH | cut -c3-4 ),
        inp%bmm=$( echo $YMDH | cut -c5-6 ),
        inp%bdd=$( echo $YMDH | cut -c7-8 ),
        inp%bhh=$( echo $YMDH | cut -c9-10 ),
        inp%model=17,
        inp%modtyp='regional',
        inp%lt_units='hours',
        inp%file_seq='multi',
        inp%nesttyp='moveable'/
&atcfinfo atcfnum=81,atcfname='HWRF',
          atcfymdh=$YMDH,atcffreq=300/
&trackerinfo trkrinfo%westbd=,
      trkrinfo%eastbd=,
      trkrinfo%northbd=,
      trkrinfo%southbd=,
      trkrinfo%type='tracker',
      trkrinfo%mslpthresh=$mslpthresh,
      trkrinfo%v850thresh=$v850thresh,
      trkrinfo%gridtype='regional',
      trkrinfo%contint=$contour_interval,
      trkrinfo%out_vit='$write_vit'/
&phaseinfo phaseflag='$phaseflag',
           phasescheme='both',
           wcore_depth=1.0/
&structinfo structflag='$structflag',
            ikeflag='n'/
&fnameinfo  gmodname='hwrf',
            rundescr='20x20',
            atcfdescr='$storm$stormid'/
&verbose verb=3/
&waitinfo use_waitfor='$use_waitfor',
          wait_min_age=10,
          wait_min_size=100,
          wait_max_wait=$wait_max_wait,
          wait_sleeptime=5
          use_per_fcst_command='y',
          per_fcst_command="./deliver %[FHOUR] %[FMIN]"/
EOF
    pre=${trakwork}/out.${atcfout}
    suf=${stormenv}.${PDY}${CYL}

    # Input vitals:
    cp -pf          $vit                                    fort.12

    # Genesis vitals are disabled since HWRF only predicts one storm
    # and/or genesis case, which is specified in fort.12:
    true            >                                       fort.13
    true            >                                       fort.14

    # These two are for running with a giant combined GRIB input file:
    ln -s -f        ${gribfile}                             fort.11
    ln -s -f        ${ixfile}                               fort.31

    # The tracker's many output files:
    ln -s -f        $pre.all.$suf                           fort.61
    ln -s -f        $pre.atcf.$suf                          fort.62
    ln -s -f        $pre.radii.$suf                         fort.63
    ln -s -f        $pre.atcfunix.$suf                      fort.64
    ln -s -f        $pre.atcf_gen.$suf                      fort.66
    ln -s -f        $pre.atcf_sink.$suf                     fort.68
    ln -s -f        $pre.atcf_hfip.$suf                     fort.69
    if [[ "$write_vit" == y ]] ; then
        ln -s -f    $pre.genvitals.${PDY}${CYL}             fort.67
    fi
    if [[ "$phaseflag" == y ]] ; then
        ln -s -f    $pre.cps_parms.${PDY}${CYL}             fort.71
    fi
    if [[ "$structflag" == y ]] ; then
        ln -s -f    $pre.structure.$suf                     fort.72
        ln -s -f    $pre.fractwind.$suf                     fort.73
        ln -s -f    $pre.pdfwind.$suf                       fort.76
    fi
    if [[ "$ikeflag" == y ]] ; then
        ln -s -f    $pre.ike.$suf                           fort.74
    fi

    # Delete the old copies of the delivered track.
    rm -f "$TRACK_12HR"

    set +x
    echo " "
    echo " -----------------------------------------------"
    echo "           NOW EXECUTING TRACKER......"
    echo " -----------------------------------------------"
    echo " "
    set -x

    msg="hwrf_unified_tracker for hwrf at ${CYL}z starting now"
    postmsg "$jlogfile" "$msg"

    set +x
    echo "+++ TIMING: BEFORE hwrf_unified_tracker  ---> `date`"
    set -x

    $gettrk < $namelist
    trkret=$?
    
    set +x
    echo "+++ TIMING: AFTER  hwrf_unified_tracker  ---> `date`"
    set -x

    msg="hwrf_unified_tracker end for hwrf at ${CYL}z completed normally"
    postmsg "$jlogfile" "$msg"

    # Copy part.* files to trak.* files
    for part in part.* ; do
        $USHhwrf/hwrf_port_checksig.sh
        if [[ "$part" == 'part.*' ]] ; then
        fail "ERROR RUNNING UNIFIED_TRACKER - NO OUTPUT FILES CREATED - ABNORMAL EXIT" \
             "An error occurred while running hwrf_unified_tracker.  The" \
             "script hwrf_rttrk_partial.sh that it runs every forecast" \
             "hour did not create any part.* files in directory:" \
             $( pwd )
        fi
        trak=$( echo "$part" | sed 's,part\.,trak\.,g' )
        if ( basename "$trak" | grep -E '\.atcfunix\.' ) ; then
            copyit -all "$part" "$trak"
        else
            copyit "$part" "$trak"
        fi
    done

    if [[ ! -z "$TRACK_12HR" ]] ; then
        if [[ ! -s "$TRACK_12HR" ]] ; then
            copyit -maxhr 12 "$TRACK_PART" "$TRACK_12HR"
        fi
    fi

    if [[ "$trkret" != 0 ]] ; then
        fail "ERROR RUNNING UNIFIED_TRACKER - RETURN CODE $trkret - ABNORMAL EXIT" \
             "An error occurred while running hwrf_unified_tracker, the program" \
             "that actually gets the track.  Expected a return code of 0" \
             "but the non-zero return status $trkret was received"
    else
        cat<<EOF > "$trakwork/tracker.is.done"
Tracker completed at `date`
with exit status $trkret
EOF
    fi
fi

if [[ "$mode" == all || "$mode" == deliver ]] ; then

    cd "$trakwork"
    if [[ "$?" != 0 ]] ; then
        fail "Cannot cd into \"$gribwork\" directory"
    fi

    "${utilscript:-${NWPROD}/util/ush}/setup.sh"

    pre=${trakwork}/trak.${atcfout}
    suf=${stormenv}.${PDY}${CYL}

    if [[ ! -s "$trakwork/tracker.is.done" ]] ; then
        fail "TRACKER COMPLETION FILE IS MISSING - TRACKER JOB FAILED" \
             "The tracker job should have produced this file" \
             "if it ran correctly:" "$trakwork/tracker.is.done" \
             "but that file is empty or non-existant."
    fi
    $USHhwrf/hwrf_port_checksig.sh
  if [[ "$SENDCOM" == YES ]] ; then

      # Copy to HWRF COM directory:

      if [[ "$source" == 27 ]] ; then
          copyit   $pre.atcfunix.$suf ${nidymdh}.diagtrak.hwrf.3hourly.parent
          # Nothing more to do
          exit 0
      elif [[ "$ATMOS_DOMAINS" == 3 && "$source" == 27:9 ]] ; then
          copyit   $pre.atcfunix.$suf ${nidymdh}.diagtrak.hwrf.3hourly.dom12
          # nothing more to do
          exit 0
      else
          copyit       $pre.atcfunix.$suf ${nidymdh}.diagtrak.hwrf.3hourly
          copyit       $pre.atcfunix.$suf ${nidymdh}.trak.hwrf.3hourly
          copyit -6    $pre.atcfunix.$suf ${nidymdh}.trak.hwrf.atcfunix
#          copyit       $pre.atcf.$suf     ${nidymdh}.trak.hwrf.atcf
#          copyit       $pre.all.$suf      ${nidymdh}.trak.hwrf.all
#          copyit -rad6 $pre.atcfunix.$suf \
#                       $pre.radii.$suf    ${nidymdh}.trak.hwrf.radii
      fi

      # Append to track archives:

      gltrakarch=${gltrakarch:-${gltrkdir}/tracks.${syy}}
      tmtrakarch=${tmtrakarch:-$TRKBASE/trak/prod/tracks.all.${syy}}
      
      glatcfarch=${glatcfarch:-${gltrkdir}/tracks.atcf.${syy}}
      tmatcfarch=${tmatcfarch:-$TRKBASE/trak/prod/tracks.atcf.${syy}}
      
      glatuxarch=${glatuxarch:-${gltrkdir}/tracks.atcfunix.${syy}}
      tmatuxarch=${tmatuxarch:-$TRKBASE/trak/prod/tracks.atcfunix.${syy}}
      
      glradarch=${glradarch:-${gltrkdir}/tracks.radii.${syy}}
      tmradarch=${tmradarch:-$TRKBASE/trak/prod/tracks.radii.${syy}}
      
      mkdir -p $gltrkdir $TRKBASE/trak/prod
      
      # NOTE: New GFDL tracker (used by this script) no longer generates
      # the "all," "atcf" or "radii" format files.  Only atcfunix format
      # files are generated:

#      cat ${trakwork}/trak.${atcfout}.all.${PDY}${CYL}   >>${gltrakarch}
#      cat ${trakwork}/trak.${atcfout}.all.${PDY}${CYL}   >>${tmtrakarch}
      
#      cat ${trakwork}/trak.${atcfout}.atcf.${PDY}${CYL}  >>${glatcfarch}
#      cat ${trakwork}/trak.${atcfout}.atcf.${PDY}${CYL}  >>${tmatcfarch}
      
      # First, clean up the track (remove times after model lost vortex):
      temptrack=${trakwork}/to-global-area.atcfunix
      copyit ${trakwork}/trak.${atcfout}.atcfunix.$suf "$temptrack"

      # Then append to global track file:
      if [[ "${PARAFLAG}" == 'NO' ]] ; then
      cat "$temptrack"  >>${glatuxarch}
      fi
      cat "$temptrack"  >>${tmatuxarch}

#      cat ${trakwork}/trak.${atcfout}.radii.${PDY}${CYL} >>${glradarch}
#      cat ${trakwork}/trak.${atcfout}.radii.${PDY}${CYL} >>${tmradarch}

      # Deliver to additional NCO locations

      $USHhwrf/hwrf_port_checksig.sh
    if [[ "${PARAFLAG}" == 'YES' ]] ; then
        echo "Not delivering tracks to operational areas because you are not NCO."
    else
        navytrack=${COMOUT}/${atcfout}.${stormenv}.${PDY}${CYL}.trackeratcfunix
        navyall=${COMOUT}/${atcfout}.t${CYL}z.cyclone.trackatcfunix
        junkstring=temp.$$.$RANDOM
        copyit ${trakwork}/trak.${atcfout}.atcfunix.$stormenv.${PDY}${CYL} "$navytrack"
        #SE copyit ${trakwork}/trak.${atcfout}.atcfunix.${PDY}${CYL} "$navytrack"
        for onestorm in $( ls -1 ${COMOUT}/*.trackeratcfunix ) ; do
            cat "$onestorm"
        done > "$navyall"

        tmscrdir=$TRKBASE/$user/trak/prod
        mkdir -p ${tmscrdir}

        tmtrakstat=${tmscrdir}/tracker.prod.status
        echo "${atcfout} tracker completed okay for ${PDY}${CYL}" >>${tmtrakstat}

        export SENDDBN=${SENDDBN:-YES}
        export SENDTRACKER=${SENDTRACKER:-NO}
        if [ ${SENDDBN} = 'YES' -o ${SENDTRACKER} = 'YES' ] ; then
            $DBNROOT/bin/dbn_alert ATCFUNIX GFS_NAVY $job "$navytrack"
        fi

        # ------------------------------------------
        # Cat atcfunix files to TPC's files
        # ------------------------------------------
        #
        # We need to parse apart the atcfunix file and distribute the
        # forecasts to the necessary directories.  To do this, first
        # sort the atcfunix records by forecast hour (k6), then sort
        # again by ocean basin (k1), storm number (k2) and then
        # quadrant radii wind threshold (k12).  Once you've got that
        # organized file, break the file up by putting all the
        # forecast records for each storm into a separate file.  Then,
        # for each file, find the corresponding atcfunix file in the
        # TPC directory and dump the atcfunix records for that storm
        # in there.  NOTE: Only do this if the model run is NOT for
        # the CMC or ECMWF ensemble.  The reason is that we do NOT
        # want to write out the individual member tracks to the
        # atcfunix file.  We only want to write out the ensemble mean
        # track to the atcfunix file, and the mean track is calculated
        # and written out in a separate script.

            auxfile=${trakwork}/trak.${atcfout}.atcfunix.$stormenv.${PDY}${CYL}
        #SE auxfile=${trakwork}/trak.${atcfout}.atcfunix.${PDY}${CYL}

        sort -k6 ${auxfile} | sort -k1 -k2 -k12  >atcfunix.sorted

        old_string="XX, XX"

        ict=0
        while read unixrec
        do
            storm_string=` echo "${unixrec}" | cut -c1-6`
            if [ "${storm_string}" = "${old_string}" ]
            then
                echo "${unixrec}" >>atcfunix_file.${ict}
            else
                let ict=ict+1
                echo "${unixrec}"  >atcfunix_file.${ict}
                old_string="${storm_string}"
            fi
        done <atcfunix.sorted

          $USHhwrf/hwrf_port_checksig.sh
        if [ $ict -gt 0 ]
        then
            mct=0
            while [ $mct -lt $ict ]
            do
                let mct=mct+1
                at=` head -1 atcfunix_file.$mct | cut -c1-2 | tr '[A-Z]' '[a-z]'`
                NO=` head -1 atcfunix_file.$mct | cut -c5-6`

                tyyyy=${syyyy}

                if [ ! -d $ATCFdir/${at}${NO}${tyyyy} ]
                then
                    mkdir -p $ATCFdir/${at}${NO}${tyyyy}
                fi
                cat atcfunix_file.$mct >>$ATCFdir/${at}${NO}${tyyyy}/ncep_a${at}${NO}${tyyyy}.dat
                set +x
                echo " "
                echo "+++ Adding records to  TPC ATCFUNIX directory: $ATCFdir/${at}${NO}${tyyyy}/ncep_a${at}${NO}${tyyyy}"
                echo " "
                set -x
            done
        fi

    fi
  fi
fi
