#!/bin/bash

# sdgal: generic script to decode an SIF file and then run package
#        on architecture on the output
#  * version for Bourne/bash shell
#  This version November 12th, 2024

# Use: sdgal architecture package [-s] [-q] [-h] [-k] [-f] [-b] [-st j]
#                          [-c] [-m] [-p] [-u] [-o j] [-l secs] 
#                          [-param name=value[,name=value...]]
#                          [-force] probname[.SIF]
#
# where: options -s : run the single precision version
#                     (Default: run the double precision version)
#                -q : run the quadruple precision version (if available)
#                     (Default: run the double precision version)
#                -h : print this help and stop execution
#                -k : keep the load module after use
#                     (Default: delete the load module)
#                -c : check derivatives for errors using finite
#                     differences (default: do not check)
#                -f : use automatic differentiation in forward mode
#                -b : use automatic differentiation in backward mode
#                -m : check for memory leaks (when possible) using valgrind
#                -p : profile the code (when possible)
#                -u : update the specfile to include the latest options
#                -o : 0 for silent mode, 1 for brief description of
#                     the stages executed.
#                     (Default: -o 0)
#                -l : limit the cputime used to secs seconds
#                     (Default: 99999999 seconds)
#            -param : cast probname[.SIF] against explicit
#                     parameter settings. Several parameter
#                     settings may be given as a comma-separated
#                     list following -param or using several -param flags.
#            -force : forces setting of a parameter to the given
#                      value even if this value is not specified
#                      in the file. This option should be used
#                      with care.(Default: do not enforce).
#
#       probname      probname[.SIF] is the name of the file containing
#                     the SIF file for the problem of interest.

#  Copyright reserved, Gould/Orban/Toint, for GALAHAD productions
#  Principal authors: Nick Gould, Dominique Orban and Philippe Toint

#  History -
#   originally released pre GALAHAD Version 1.0. August 20th, 1999 (for csh)
#   update released with GALAHAD Version 2.0. August 11th 2005 (for sh)

if [[ -z $GALAHAD ]]; then
  echo ' You have not the=true GALAHAD environment variable. '
  echo ' This needs to point to the main directory in which '
  echo ' you have installed the GALAHAD package. '
  exit 5
fi

# Obtain number of arguments
let last=$#
#(( last=last-1 ))

stop_early="false"
if (( last < 2 )); then
    stop_early="true"
elif [[ "`echo $1 | grep -e '^-'`" != "" || "`echo $2 | grep -e '^-'`" != ""  ]]; then
    stop_early="true"
fi

if [[ "$stop_early" == "true" ]]; then
    echo ' Use: sdgal architecture package [-s] [-q] [-h] [-k] [-f] [-b]' 
    echo '                 [-st j] [-c] [-m] [-p] [-u] [-o j] [-l secs]'
    echo '                 [-param name=value[,name=value...]]'
    echo '                 [-force] probname[.SIF]'
    exit 1
fi

if [[ $2 == 'lancelot' || $2 == 'lancelot_steering' ]]; then
  METHARG="-A $1 -p 0"
else
  METHARG="-A $1 "
fi

#  directory for temporary files

TMP=/tmp

#  variables for each option

#  LIMIT (maximum cputime for running object file)

LIMIT=99999999
#LIMIT=1800

# PRECISION = 0 (single precision), = 1 (double precision), 
#           = 2 (quadruple precision)

PRECISION=1

# UPDATE = 0 (use existing specfile),
#        = 1 (update specfile to include latest options)

UPDATE=0

#   AUTOMATIC = 0 (provided), = 1 (automatic forward), = 2 (automatic backward)

AUTOMATIC=0
AD0=2

# KEEP = 0 (discard load module after use), = 1 (keep it)

KEEP=0

# MEMCHECK = 0 (do not grind the code for memory leaks), = 1 (grind it)

MEMCHECK=0

# PROFILE = 0 (do not profile the code), = 1 (profile it)

PROFILE=0

# OUTPUT = 0 (summary output), = 1 (detailed output from decoder)

OUTPUT=0

#  starting point vector to be used; if start > # starting vectors, start = 1

START=1

let i=3

while (( i <= last ))
do
  opt=${!i}
#  echo " opt = $opt"
  if [[ "$opt" == '-h' || "$opt" == '--help' ]]; then
    echo ' Use: sdgal architecture package [-s] [-q] [-h|--help] [-k] [-f] [-b]'
    echo '          [-st start] [-m] [-p] [-u] [-o j] [-l secs]'
    echo '          [-param name=value[,name=value...]] [-force] probname[.SIF]'
    echo ' '
    echo ' where: options -s : run the single precision version'
    echo '                     (Default: run the double precision version)'
    echo '                -q : run the quadruple precision version (if available)'
    echo '                     (Default: run the double precision version)'
    echo '                -h : print this help and stop execution'
    echo '                -k : keep the load module after use '
    echo '                     (Default: delete the load module)'
    echo "                -c : check derivatives for errors using finite"
    echo "                     differences (default: do not check)"
    echo '                -f : use automatic differentiation in forward mode'
    echo '                -b : use automatic differentiation in backward mode'
    echo "                -st : starting point vector to be used"
    echo "                    (Default: -st 1)"
    echo '                -m : check for memory leaks (when possible) using valgrind'
    echo '                -p : profile the code (when possible)'
    echo '                -u : update the specfile to include the latest options'
    echo '                -o : 0 for silent mode, 1 for brief description of'
    echo '                     the stages executed'
    echo '                     (Default: -o 0)'
    echo '                -l : limits the cputime to secs seconds'
    echo '                     (Default: unlimited cputime)'
    echo "                -param : cast probname[.SIF] against explicit"
    echo "                         parameter settings. Several parameter"
    echo "                         settings may be given as a comma-separated"
    echo "                         list following -param or using several"
    echo "                         -param flags."
    echo "                -force : forces setting of a parameter to the given"
    echo "                          value even if this value is not specified"
    echo "                          in the file. This option should be used"
    echo "                          with care.(Default: do not enforce)."
    echo ' '
    echo '       probname      probname.SIF is the name of the file containing'
    echo '                     the SIF file for the problem of interest.'
    exit 0
  elif [[ "$opt" == '-s' ]]; then
    PRECISION=0
    METHARG="$METHARG -sp"
  elif [[ "$opt" == '-q' ]]; then
    PRECISION=2
    METHARG="$METHARG -qp"
  elif [[ "$opt" == '-u' ]]; then
    UPDATE=1
  elif [[ "$opt" == '-c' ]]; then
    METHARG="$METHARG -c"
  elif [[ "$opt" == '-f' ]]; then
    AUTOMATIC=1
  elif [[ "$opt" == '-b' ]]; then
    AUTOMATIC=2
  elif [[ "$opt" == '-st' ]]; then
    (( i++ ))
    START=${!i}
    METHARG="$METHARG -st $START"
  elif [[ "$opt" == '-k' ]]; then
    KEEP=1
  elif [[ "$opt" == '-m' ]]; then
    MEMCHECK=1
  elif [[ "$opt" == '-p' ]]; then
    PROFILE=1
  elif [[ "$opt" == '-o' ]]; then
    (( i++ ))
    OUTPUT=${!i}
    METHARG="$METHARG -o $OUTPUT"
  elif [[ "$opt" == '-l' ]]; then
    (( i++ ))
    LIMIT=${!i}
    METHARG="$METHARG -l $LIMIT"
  elif [[ "$opt" == '-a' ]]; then
    (( i++ ))
    AD0=${!i}
    METHARG="$METHARG -a 2"
  elif [[ "$opt" == '-param' ]]; then
    (( i++ ))
    PARAM=${!i}
    METHARG="$METHARG -param $PARAM"
  elif [[ "$opt" == '-force' ]]; then
    METHARG="$METHARG -force"
  fi
  (( i++ ))
done

#echo $METHARG

# call with two argument allows user to choose minimization method

if [[ $PRECISION == "1" ]]; then
 p=""
 up="d"
 PRECIS=double
elif [[ $PRECISION == "2" ]]; then
 p="-q"
 up="q"
 PRECIS=quadruple
else
 p="-s"
 up="s"
 PRECIS=single
fi

#  machine-dependent bits

eval "`cat $GALAHAD/bin/sys/$1`"
#. $GALAHAD/bin/sys/$1

if [[ $AUTOMATIC == "1" ]]; then
  METHARG="$METHARG -f -m 0"
elif [[ $AUTOMATIC == "2" ]]; then
  METHARG="$METHARG -b -m 0"
fi

if [[ $KEEP == "1" ]]; then
 k="-k"
else
 k=""
fi

if [[ $MEMCHECK == "1" ]]; then
 mem="-m"
else
 mem=""
fi

if [[ $PROFILE == "1" ]]; then
 pro="-p"
else
 pro=""
fi

if [[ $UPDATE == "1" ]]; then
 update="-u"
else
 update=""
fi

probname=${!#}
#probname=${@[$last]}

if [[ $OUTPUT == "1" ]]; then
  echo 'convert the sif file into data and routines suitable for optimizer...'
  echo ' '
  echo 'problem details will be given'
  echo ' '
fi

[[ -e EXTER.f ]] && $RM EXTER.f

# decode the problem

if [[ ! -z $SIFDECODE  ]]; then
  $SIFDECODE/bin/sifdecoder $METHARG $probname
  [[ $? != 0  ]] && exit $status
else
  echo " sdgal : environment variable SIFDECODE not set"
  echo "         Either SIFDecode is not installed or you"
  echo "         need to properly set SIFDECODE"
  exit 4
fi

#  Check for decoding errors

[[ $OUTPUT == "1" ]] && echo ' '
if [[ ! -e OUTSDIF.d ]]; then
  echo ' '
  echo "error exit from decoding stage. terminating execution."
  exit 3
fi
[[ $OUTPUT == "1" ]] && echo ' '

#  Record the type of derivatives used in the decoding

[[ -f AUTOMAT.d ]] && $RM AUTOMAT.d
echo $AUTOMATIC $AD0 > AUTOMAT.d

#  run the program on the output

$GALAHAD/bin/gal $1 $2 $p $k $update $mem $pro -o $OUTPUT -l $LIMIT

$RM $TMP/sdgal.input

