#!/bin/bash -f
#  Version: 09/10/05
#  Eric's data assimilation script for doing simple parallelization on
#  Beowulf clusters.
#  Command line:  [options] atime
#  where atime is the analysis time in the form yyyymmddhh.
#  This file reads a configuration file for many of its inputs.
#  The configuration filename is 'config', but it may be specified
#  with the -C option.  All of the assimilation variables may be specified
#  in the config file.  It is also possible to override some of the config file
#  variables by specifying the appropriate command-line options.
#  The -h flag can be given to print out a list of command-line options
#  and to summarize the variables listed in the config file.
#  The configuration allows filenames to be specified by the assimilation time,
#  date, or hour.  We define ATIME=yyyymmddhh, ADATE=yyyymmdd, and AHOUR=hh.
#  
#  We look for "forecast" sigma files, which end in .hh (which is .06
#  for a 6-hr forecast, for instance), then assimilate the data and create
#  an analysis in the same directory whose files end in .00; these serve as
#  new initial conditions.
#
#  Output goes into RESULTDIR and consists of files
#  with the template name "sigma" as given in the config file.
#  In both cases, observations are taken from files whose name is given
#  by obsname; the latter variable is specified in the config file.
#  
#  Example:  beo_assim [options] 2003011706
#  takes 6-hour forecast sigma files, which represent the output from the MRF
#  program, assimilates the observations at 6Z on 01/17/2003, and
#  places sigma_out files in RESULTDIR.  The sigma_out files can be used
#  as input for the next forecast cycle.
#
#  Notes:
#
#  -Variables in UPPER CASE are command-line arguments.  Those in lower case
#  are internal to the script or are read from the config file.
#
#  Required executables:
#  run_assim_p - utility script
#  ndate   - utility script
#  fcstsuffix - utility script
#  preanalysis - sigma file -> grid file converter
#  assim_p - data assimilation program
#  postanalysis - grid file -> sigma file converter

version="09/10/05"
action="all"   # perform preprocessing, assimilation, and postprocessing
display_command_lines="no"    # don't display all progress by default

#set -x
#
#  I/O units that may need byte-swapping.  See the conventions
#  in support/io.f90.  This is Lahey-specific.
#
INSWAP=1
OUTSWAP=2
export FORT90L="-Wl,-T$INSWAP,-T$OUTSWAP"

# We need a configuration file to run, because not all the required
# variables can be set from the command line.
# beo_assim -C file -h
# displays the contents of file that can be altered from the command line
CONFIG=config

# ---------------------------------------
function template_name { # replace %n in $1 with the decimal integer value in $2
   echo $1 $2 | awk '{if(sub(/%n/, $2, $1)>0) {print $1} else {print $1$2}}'
   return
}  #template_name
# ---------------------------------------
#  EXPAND - expand a quoted value using current variables, especially ATIME
#  and its derivatives.
#  Optional arguments allow for temporary overrides of variables named
#  in the first argument.

function expand {  
   local v=$1
   local prev=""
   local var 

   shift 1
   for var in $*
   do
      local $var
   done
   local ADATE=$(echo $ATIME | cut -c 1-8)
   local AHOUR=$(echo $ATIME | cut -c 9-10)

   while [ "$prev" != "$v" ]
   do
      prev=$v
      v=$(eval echo $v)
   done
   echo $v
   return
}  #expand
# ---------------------------------------
function prevexpand {  # like expand, but use the previous time step
   local t=$ATIME
   ATIME=$($scriptdir/ndate -$fcsttime $t)
   local v=$(expand $1)
   ATIME=$t
   echo $v
}
# ---------------------------------------
function usage {
    echo "Usage: $0 [options] atime"
    echo "Version: $version"
    echo "Options:"
    echo "-h (to print this message)"
    echo "-C config_file (current: $CONFIG)"
    echo "-X exedir:scriptdir"
    echo "-p action (possibilities are -pre, -post and -proc)"
    echo "    for preprocess only, postprocess only, or run assimilation only"
    echo "-v displays selected command lines as they are executed"
    echo "-f (only valid at start time: convert startphys files to sigma)"
    echo "atime (yyyymmddhh format; or 0 for default starttime)"
    echo "Command-line values override those in any config file."
    CONFIG=${CL_CONFIG:-$CONFIG}
    if [ ! -f $CONFIG ]
    then
       echo "$0: No configuration file specified" 1>&2
       exit 1
    else
       echo "$0: Configuration file: " $CONFIG
       . $CONFIG
    fi
    echo "Config file variables:"
    echo "exedir: $exedir"
    echo "scriptdir: $scriptdir"
    echo "RESULTDIR: $RESULTDIR"
    echo "VERBLEV: $VERBLEV"
    echo "ZRAD:" $(expand $ZRAD)
    echo "XWIDTH: $XWIDTH"
    echo "YWIDTH: $YWIDTH"
    echo "NSOL: $NSOL"
    echo "PROCLIST: $PROCLIST"
    echo "NPROC: $NPROC"
    echo "sigma file basenames: $sigma"
    echo "truesigma: $truesigma"
    echo "OBSDIR: $OBSDIR"
    echo "OBS_TEMP_UNITS: ${OBS_TEMP_UNITS:-K}"
    echo "obsfile: $obsfile"
    echo "obs_consistency_check: $obs_consistency_check"
    echo "sigma_mean: $sigma_mean"
    echo "unassim_sigma: $unassim_sigma"
    echo "diag: $diag"
    echo "SCRATCHDIR:" $SCRATCHDIR
    echo "natgrid: $natgrid"
    echo "errlog: $errlog"
    echo "log: $log"
    echo "egrid: $egrid"
    echo "egrid_out: $egrid_out"
    echo "yobs: $yobs"
    echo "ERRTHRESH: $ERRTHRESH"
    exit 1
}
#-------------------------------------------------------------------------
function startup {
   # command-line specifications, if any
   CL_CONFIG=
   CL_EXEDIR=
   while getopts C:fhp:X:v opt
   do
       case $opt in
       C)  CL_CONFIG=$OPTARG;;
       f)  run_initial_forecast="true" ;;
       h)  usage;;
       p)  case $OPTARG in
           re)   action="pre";;
           ost)  action="post";;
           roc)  action="proc";;
           *) echo "unknown action -p$OPTARG" 1>&2;
              exit 1;;
           esac ;;
       X)  echo "got $opt" ; CL_EXEDIR=$OPTARG;;
       v)  display_command_lines="yes"
       esac
   done

   #  Read the configuration file.  Use the one named in the command line,
   #  if specified.

   CONFIG=${CL_CONFIG:-$CONFIG}
   if [ ! -f $CONFIG ]
   then
      echo "$0: Cannot find configuration file $CONFIG"  1>&2
      exit 1
   else
      . $CONFIG
   fi

   #  Time ourselves
   if [ $VERBLEV -gt 0 ]
   then
      wallclock=$(date +%s)   # GNU: wall clock time in sec since epoch
   fi

   # Override the execution path in the config file with any command-line
   # specification.
   export PATH=${CL_EXEDIR:-$exedir}:$PATH

   # get analysis time; required argument that comes last on the command line
   # the format is ATIME=yyyymmddhh.

   shift $(expr $OPTIND - 1)
   ATIME=$1
   if [ -z "$ATIME" ]
   then
      echo "$0: analysis time not specified" 1>&2
      usage
      exit 1
   fi

   # check that ATIME is in a valid format (either 0 or yyyymmddhh)

   if [ $ATIME -ne 0 ]
   then
      if ! $scriptdir/ndate 0 $ATIME > /dev/null
      then
         echo $0: invalid format for ATIME
         exit 1
       fi
    fi

   #use default starting date if ATIME=0

   if [ $ATIME -eq 0 -o $ATIME -eq $starttime ]
   then
      first=1
      ATIME=$starttime
      echo "$0: using initialization data for $starttime" 1>&2
   else
      first=0
   fi
   ADATE=$(echo $ATIME | cut -c 1-8)  # yyyymmdd portion
   AHOUR=$(echo $ATIME | cut -c 9-10) # hh portion

   # Expand quoted values in config file.
   # IMPORTANT: most of the work files here should go to the raid,
   # i.e., RESULTDIR, so that we can run this script from a node
   # that is listed in the PROCLIST.  

   resultdir=$(expand $RESULTDIR)
   if [ ! -d $resultdir ]
   then
      if ! mkdir -p $resultdir
      then
         echo $0: error creating $resultdir 1>&2
         exit 1
      fi
   fi
   configdir=$(dirname $resultdir)
   truesigma=$(expand $truesigma)
   obsfile=$(expand $obsfile)
   sigma_mean=$(expand $resultdir/$sigma_mean)
   diag=$(expand $resultdir/$diag)
   if [ -n "$natgrid" ]
   then
      natgrid=$(expand $resultdir/$natgrid)
   else
      natgrid=
   fi
   errlog=$(expand $resultdir/$errlog)
   log=$(expand $resultdir/$log)
   egrid=$(expand $resultdir/$egrid)
   egrid_out=$(expand $resultdir/$egrid_out)
   yobs=$(expand $resultdir/$yobs)
   if [ -n "$ZRAD" ]
   then
      zrad=$configdir/$(expand $ZRAD)
      if [ ! -f $zrad ]
      then
         echo $0: vertical localization data file $zrad not found 1>&2
         exit 1
      fi
   fi
   if [ -n "$debug_egrid_out" ]
   then
      debug_egrid_out=$(expand $resultdir/debug_egrid_out)
   fi

   ztemp=""

   nodes=$(nodelist -n $PROCLIST)
   let "avail=nodes*procpernode"
   if [ $avail -lt $NPROC ]
   then
       echo "$0: $NPROC processors requested; only $avail available" 1>&2
       exit 1
   fi

   #  intuit possible errors
   if [ -n "$natgrid" -a -z "$diag" ]
   then
       echo "$0: warning: nature grid specified without a diagnostics file" 1>&2
   fi

   #  initialize - don't split into more pieces than we have processors
   let "maxproc=nodes*procpernode"
   if [ $NPROC -gt $maxproc ]
   then
       NPROC=$maxproc
   fi

   #  Check defaults
   refsig=$(expand $refsig)
   if [ ! -f $refsig ]
   then
      echo "$0: Cannot find reference sigma file $refsig" 1>&2
      exit 1
   fi

   #  Make sure the scratch directory exists on the host node
   mkdir -p $SCRATCHDIR
   if [ $? -ne 0 ]
   then
      echo $0: cannot create scratch directory $SCRATCHDIR 1>&2
      echo $0: Note: this script cannot be run on the master node 1>&2
      exit 1
   fi

   mkdir -p $resultdir
   if [ $? -ne 0 ]
   then
      echo $0: cannot create result directory $resultdir 1>&2
      exit 1
   fi
   return
}
#-------------------------------------------------------------------------
function preprocess {
#  Preprocessing step.  The usual procedure is to
#  create physical ensemble grid from previous 6-hour forecast sigma files.
#  Special case: when we first start up (ATIME=starttime), we do an
#  assimilation step into the starting sigma/physical grid files.
#
   suffix=$($scriptdir/fcstsuffix $fcsttime)
   if [ "$ATIME" -eq $starttime ]
   then
      if [ -n "$startsigma" ]   # starting with sigma files
      then
         fcstsigma=$(expand $startsigma)
         pre_args="-n $NSOL -b $egrid -v $VERBLEV \
            -p $NPROC -y $YWIDTH $fcstsigma"
      else  # starting with physical perturbation files
         startphys=$(expand $startphys)
         pre_args="-n $NSOL -b $egrid -v $VERBLEV \
            -p $NPROC -y $YWIDTH -P $startphys"
      fi
   else
      fcstsigma=$(prevexpand $RESULTDIR)/$sigma.$suffix
      pre_args="-n $NSOL -b $egrid -v $VERBLEV -p $NPROC -y $YWIDTH $fcstsigma"
   fi
   if [ "$display_command_lines" = yes ]
   then
      echo preprocessing:
      echo preanalysis $pre_args
   fi
   preanalysis $pre_args
   errcode=$?
   if [ $errcode -ne 0 ]
   then
      echo $0: $ATIME: error creating background grid 1>&2
      exit $errcode
   fi
   if [ -n "$natgrid" ]
   then
      if [ "$display_command_lines" = yes ]
      then
         echo nature grid:
         echo preanalysis -n1 -b $natgrid -v $VERBLEV -H true -p $NPROC \
            -y $YWIDTH $truesigma
      fi
      preanalysis -n1 -b $natgrid -v $VERBLEV -H true -p $NPROC \
         -y $YWIDTH $truesigma
      errcode=$?
      if [ $errcode -ne 0 ]
      then
         echo $0: $ATIME: error creating \"nature\" grid 1>&2
         exit $errcode
      fi
   fi

   #  Create gridded observation file from previously-generated observations
   if [ "$display_command_lines" = yes ]
   then
      echo observation grid:
      echo preanalysis -A $OBSTYPE -o $yobs -v $VERBLEV -p $NPROC \
         -y $YWIDTH $obsfile
   fi
   preanalysis -A $OBSTYPE -o $yobs -v $VERBLEV -p $NPROC -y $YWIDTH $obsfile
   errcode=$?
   if [ $errcode -ne 0 ]
   then
      echo $0: $ATIME: error creating observations 1>&2
      exit $errcode
   fi
   if [ $VERBLEV -gt 0 ]
   then
      now=$(date +%s)
      let "now=now-wallclock"
      echo "$0: preanalysis time: $now sec"
   fi
   return
}
#-------------------------------------------------------------------------
function assimilate {
#  Run the data assimilation algorithm

   if [ $VERBLEV -gt 0 ]
   then
      pstart=$(date +%s)   # GNU: wall clock time in sec since epoch
   fi

   #  Make a list of the available machines
   declare -a machlist=($(nodelist -p $NODE $PROCLIST))  # bash only

   if [ $NPROC -gt 1 ]   # usual case: multiple processors
   then
       if [ $VERBLEV -gt 0 ]
       then
          echo "$0: version ${version}: starting assimilations"
          echo "$0: assimilation code: $exedir/assim_p"
          echo -n "$0: processor "
       fi
       n=0

       # Copy split grid files to each node, which we discard after use.
       # The diagnostics file is a special case: the split versions
       # are scratch files, which we copy back and concatenate into
       # a final version at the end.
       while [ $n -lt $NPROC ]
       do
           let "idx=n/procpernode"
           let "np1=n+1"   # split files are indexed from 1, not 0
           mach=${machlist[$idx]}

           egridbase[$np1]=$egrid$np1
           analbase[$np1]=$egrid_out$np1
           yobsbase[$np1]=$yobs$np1
           if [ -n "$diag" ]
           then
              diagbase[$np1]=$diag.$np1
           else
              diagbase[$np1]=""
           fi
           if [ -n "$natgrid" ]
           then
              truthbase[$np1]=$natgrid$np1
           else
              truthbase[$np1]=""
           fi

           # Build options onto the command line incrementally.
	# Start with temperature units, whose default is Kelvin.
           options="-T ${OBS_TEMP_UNITS:-K}"

	# observation types to assimilate, specified in config file
	if [ -n "$OBSTYPE" ]
	then
	   options="$options -A $OBSTYPE"
	fi

	# observation consistency checks, if any
	if [ -n "$obs_consistency_check" ]
	then
	   options="$options -c $obs_consistency_check"
	fi

           #  Vertical localization z radii file, if any
           if [ -n "$zrad" ]
           then
              options="$options -z $zrad"
           fi

           #  Launch the assimilations and track the exit codes.
           #  Handle the "true" grid and diagnostics files, if any.
           if [ -n "${truthbase[$np1]}" ]
           then
              options="$options -t ${truthbase[$np1]}"
           fi
           if [ -n "${diagbase[$np1]}" ]
           then
              options="$options -d ${diagbase[$np1]}"
           fi
           options="$options -e ${errlog}.$np1 -L ${log}.$np1"

           #  run_assim_p deletes temporary files on remote nodes, so we don't
           #  need to handle the cleanup here.  Give the full pathname,
           #  as PATH initialization may be different when running under rsh.
           #  Note that the processing here is done in the background;
           #  we wait for the processes to finish at the end of the while loop.
           #  Also note: assignments of the form
           #  errcode[$np1]=$( command || echo \$?) &
           #  don't work.  So we have an ugly hack of creating a temporary file
           #  to hold the exit code.
            
           rm -f $SCRATCHDIR/howdid.$np1
	if [ "$display_command_lines" = yes ]
           then
	   echo $scriptdir/run_assim_p -r $resultdir -N $mach \
               -P $exedir -E $ERRTHRESH -x $XWIDTH -y $YWIDTH \
               -b ${egridbase[$np1]} -o ${yobsbase[$np1]} -a ${analbase[$np1]} \
               -n $NSOL -v $VERBLEV $options -q $SEQID 
	fi
           $scriptdir/run_assim_p -r $resultdir -N $mach \
               -P $exedir -E $ERRTHRESH -x $XWIDTH -y $YWIDTH \
               -b ${egridbase[$np1]} -o ${yobsbase[$np1]} -a ${analbase[$np1]} \
               -n $NSOL -v $VERBLEV $options -q $SEQID \
               || echo error exit $? > $SCRATCHDIR/howdid.$np1 &
           let "n=n+1"
	sleep 5  # delay to give the raid a running start
           if [ $VERBLEV -gt 0 ]   # display processor count to log or tty
           then
              echo -n $n ' '
           fi
      done
      if [ $VERBLEV -gt 0 ]
      then
         echo 
      fi
      #  MRF output files could be copied from /scratch to /raid here
      wait

      #  Check return codes and quit on error.  
      quitnow=no
      n=0
      while [ $n -lt $NPROC ]
      do
         let "np1=n+1"
         if [ -f $SCRATCHDIR/howdid.$np1 ]
         then
            errcode=$(< $SCRATCHDIR/howdid.$np1)
            rm -f $SCRATCHDIR/howdid.$np1
            if [ -n "$errcode" ]
            then
               echo "$0: $ATIME: $errcode in assim on processor $np1" 1>&2
               quitnow=yes
            fi
         fi
         let "n=n+1"
      done
      if [ "$quitnow" = yes ]
      then
         echo $0: $ATIME: quitting on assimilation errors 1>&2
         exit 1
      fi

      #  Concatenate the separate diag files, each of which is now
      #  in the result directory, into one diag file.
      if [ -n "$diag" ]
      then
         mv $diag.1 $diag
         n=1
         while [ $n -lt $NPROC ]
         do
            let "np1=n+1"
	 cat ${diagbase[$np1]} >> $diag
	 rm ${diagbase[$np1]} 
            let "n=n+1"
         done
      fi

   #  Otherwise run the assimilation on a single processor
   else
      if [ $VERBLEV -gt 0 ]
      then
         echo "$0: version ${version}: starting assimilations on one processor"
      fi
      options="-T ${OBS_TEMP_UNITS:-K}"  # default Kelvin
      if [ -n "$zrad" ]
      then
         options="$options -z $zrad"
      fi
      if [ -n "$natgrid" ]
      then
         options="$options -t $natgrid"
      fi
      if [ -n "$diag" ]
      then
         options="$options -d $diag"
      fi
      #  Random perturbations at surface, if any
      if [ -n "$randpert" ]
        then
           options="$options -r $randpert"
      fi
      egrid=$SCRATCHDIR/egrid
      egrid_out=$SCRATCHDIR/egrid.out
      yobs=$SCRATCHDIR/yobs
      if [ "$display_command_lines" = yes ]
      then
         echo "assim_p -b $egrid -o $yobs -a $egrid_out -e $ERRTHRESH 
           -x $XWIDTH -y $YWIDTH -n $NSOL 
           -v $VERBLEV $options 1>$log 2>$errlog"
      fi
      assim_p -b $egrid -o $yobs -a $egrid_out -e $ERRTHRESH \
           -x $XWIDTH -y $YWIDTH -n $NSOL \
           -v $VERBLEV $options 1>$log 2>$errlog
      ek=$?
      if [ $ek -ne 0 ]
      then
          echo $0: $ATIME: exit code $ek performing analysis 1>&2
          exit $ek
      fi
      rm -f $egrid $yobs $natgrid  #delete working files on local node
   fi
   if [ $VERBLEV -gt 0 ]
   then
      now=$(date +%s)
      let "pstart=now-pstart"
      echo "$0: assimilation step wall clock time: $pstart sec"
   fi
   return
}
#-------------------------------------------------------------------------
function postprocess {
   #  Postprocessing step.
   #  refsig is the sigma file from the nature run that we'll use to incorporate
   #  any variables that we don't assimilate.

   #  Assemble the analyzed strips and clean up output grid files

   if [ $VERBLEV -gt 0 ]
   then
      pstart=$(date +%s)   # GNU: wall clock time in sec since epoch
   fi
   if [ "$run_initial_forecast" = true ]   # convert pert files ->sigma
   then
      options="-P"
      grid_family=$(expand $startphys)
   else
      options=""
      grid_family=$egrid_out
   fi
   if [ -n "$sigma_mean" ]    # create a sigma file for the analysis mean
   then
      options="$options -m $sigma_mean"
   fi
   if [ -n "$debug_egrid_out" ]
   then
      options="$options -g $debug_egrid_out"
   fi
 
   #  Surface boundary files are created AFTER a forecast is run.
   #  So the mean surface analysis is run on the PREVIOUS time step.
   if [ -n "$sfc" ]
   then
      if [ "$ATIME" -gt "$starttime" ]
      then
         suffix=$($scriptdir/fcstsuffix $fcsttime)
         s=$(prevexpand $RESULTDIR)/$(expand $sfc).$suffix
         options="$options -S $s"
      fi
   fi
   suffix=$($scriptdir/fcstsuffix 0)  # these are the new initial conditions
   sigma_out=$resultdir/$sigma.$suffix
   if [ "$ATIME" = "$starttime" ]
   then
      refsig=$truesigma  #need this for startup regardless
   elif [ "$unassim_sigma" = background ] 
   then   # copy unassimilated variables from background
      suffix=$($scriptdir/fcstsuffix $fcsttime)
      fcstsigma=$(prevexpand $RESULTDIR)/$sigma.$suffix
      refsig=$fcstsigma  
   else
      refsig=$truesigma  # otherwise from nature run
   fi

   if [ $NPROC -gt 1 ]
   then
      #  Post-process the NPROC assimilated data files into sigma files for the
      #  next forecast step.

      # Let the output binary files from postanalysis be big-endian.
      if [ "$display_command_lines" = "yes" ]
      then
         echo "postanalysis:"
         echo postanalysis -d $ATIME -f $refsig -n $NSOL -v $VERBLEV \
            -p $NPROC $options -s $sigma_out $grid_family
      fi
      postanalysis -d $ATIME -f $refsig -n $NSOL -v $VERBLEV -p $NPROC \
         $options -s $sigma_out $grid_family
      errcode=$?
      if [ $errcode -ne 0 ]
      then
         echo $0: $ATIME: error postprocessing analysis 1>&2
         exit $errcode
      fi

      #  Delete split egrid files
      n=0
      while [ $n -lt $NPROC ]
      do
         let "np1=n+1"
         rm -f $egrid_out$np1
         let "n=n+1"
      done

   else  # postprocess the single output grid file.

      # Let the output binary files from postanalysis be big-endian.
      if [ "$display_command_lines" = "yes" ]
      then
         echo "postanalysis:"
         echo postanalysis -d $ATIME -f $refsig -n $NSOL -v $VERBLEV $options \
            -s $sigma_out $grid_family
      fi
      postanalysis -d $ATIME -f $refsig -n $NSOL -v $VERBLEV $options \
         -s $sigma_out $grid_family
      errcode=$?
      if [ $errcode -ne 0 ]
      then
         echo $0: $ATIME: error postprocessing analysis 1>&2
         exit $errcode
      fi
      rm -f $egrid_out
   fi

#  Create grib file for visualization.  2004 model only: for now, we use
#  only the flux file for the first ensemble member, rather than the
#  mean flux.
   res=$(expand $RESULTDIR)
   smean=$(expand $sigma_mean)   # from config
   gmean=$(expand $grib_mean)   # from config
   scratchdir=$(expand $SCRATCHDIR)  # from config
   postdir=$scratchdir/postprocess
   if [ ! -d $postdir ]
   then
      mkdir -p $postdir
   fi
   #  fluxfile and "0" (indicates analysis sigma file) are 
   #  used only for the 2004 model version

   if ! $scriptdir/postgrib.$MODEL $postdir/runpost $res/$(basename $smean) \
       $res/$(basename $gmean) $(template_name $flux 1) 0
   then
      echo $0: postprocessing failed at $(date) 1>&2
      exit 1
   fi
   if [ $VERBLEV -gt 0 ]
   then
      now=$(date +%s)
      let "pstart=now-pstart"
      echo "$0: postprocessing time: $pstart sec"
      let "now=now-wallclock"
      echo "$0: total wall clock time: $now sec"
   fi
   return
}
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
#  Main algorithm.

exedir=none
startup $*   # parse execute line - must be passed as an argument!
case $action in
   all)  preprocess; assimilate; postprocess;;
   pre)  preprocess;;
   proc) assimilate;;
   post) postprocess;;
esac

exit 0
