#! /bin/bash
#
# Copyright 2007 Parallel Quantum Solutions, Fayetteville, Arkansas, USA
#
# http://www.pqs-chem.com
#
# sales@pqs-chem.com
#
# Script to launch a PQS calculation.
# It can be used to run serial jobs or parallel jobs using PVM.
# The scripts looks for the PQS environmental variables and sets
# them to default values if they are not defined.
# It checks for the presence of the input file and
# it generates an error if it is not found.
# Before running a job, an exixting .out file will
# be appended to the corresponding .old file
#
# Default PQS_ROOT value
#
if [ -z "$PQS_ROOT" ]; then
        export PQS_ROOT=/usr/local/share/PQS
fi
#
# Default PQS_SCRDIR value
#
if [ -z "$PQS_SCRDIR" ]; then
        export PQS_SCRDIR=/scr/${USER}
fi
#
# Default PQS_BASDIR value
#
if [ -z "$PQS_BASDIR" ]; then
        export PQS_BASDIR=${PQS_ROOT}/BASDIR
fi
#
# function to print the help message
#
PrintHelp()
{
  echo
  echo "USAGE:"
  echo "Single-processor jobs:"
  echo "       pqs molecule-name"
  echo
  echo "Parallel jobs:"
  echo "       pqs molecule-name nslaves [-f machine-file] [-pvm | -mpi1 | -mpi2]"
  echo
  echo "       the default parallel environment is PVM"
  echo
  exit 0
}
#
# function to pass an argument to the PQS executables (-v, -c)
#
RunArgument()
{
  echo
  echo "PQS serial:"
  echo
  ${PQS_ROOT}/pqs.x $1
  if [ -x "${PQS_ROOT}/pqs_pvm.x" ];then
        echo
        echo "PQS Parallel (PVM):"
        echo
        ${PQS_ROOT}/pqs_pvm.x $1
  fi
  if [ -x "${PQS_ROOT}/pqs_mpi1.x" ];then
        echo
        echo "PQS Parallel (MPICH1):"
        echo
        ${PQS_ROOT}/pqs_mpi1.x $1
  fi
  if [ -x "${PQS_ROOT}/pqs_mpi2.x" ];then
        echo
        echo "PQS Parallel (MPICH2):"
        echo
        ${PQS_ROOT}/pqs_mpi2.x $1
  fi
  echo
  exit 0
}
#
# function to get the job name
#
GetJobName()
{
  jobname=${1//%.input}
  jobname=${jobname//%.inp}
  jobname=${jobname//%.com}
  jobname=${jobname//%.pqs}
}
#
# function to get the input name
#
GetInputName()
{
  if [ -r "$1" ]; then
          inpname=$1;
  elif [ -r "$1.input" ]; then
          inpname=$1.input;
  elif [ -r "$1.inp" ]; then
          inpname=$1.inp;
  elif [ -r "$1.com" ]; then
          inpname=$1.com;
  elif [ -r "$1.pqs" ]; then
          inpname=$1.pqs;
  else
          echo
          echo "Cannot find the PQS input file for '$1'."
          echo "Valid input names are:"
          echo "'$1.input'"
          echo "'$1.inp'"
          echo "'$1.com'"
          echo "'$1.pqs'"
          echo 
          echo  "Please make sure one of these files exists and is readable."
          echo 
          exit 1;
  fi
}
#
# function to run a serial job
#
RunSerial()
{
  ${PQS_ROOT}/pqs.x "$1"  > console-messages 2>&1
}
#
# function to run a PVM job
#
RunPVM()
{
  if [ -n "$3" ]; then
          ${PQS_ROOT}/pqs_pvm.x -f "$3" -np $2 "$1"  > console-messages 2>&1
  else
          echo reset | pvm > /dev/null
          echo "The PVM virtual machine has been reset"
          ${PQS_ROOT}/pqs_pvm.x -np $2 "$1"  > console-messages 2>&1
  fi
}
#
# function to run a MPICH1 job
#
RunMPI1()
{
  if [ -n "$3" ]; then
          mpirun -np $2 -machinefile "$3" ${PQS_ROOT}/pqs_mpi1.x "$1"  > console-messages 2>&1
  else
          mpirun -np $2 ${PQS_ROOT}/pqs_mpi1.x "$1"  > console-messages 2>&1
  fi
}
#
# function to run a MPICH2 job
#
RunMPI2()
{
  mpiexec -np $2 ${PQS_ROOT}/pqs_mpi2.x "$1"  > console-messages 2>&1
}
#
# Consistency check for the input arguments
#
if [ $# == 0 ]; then
        PrintHelp;
fi
#
# argument processing
#
P_TYPE=1 # the default parallel environment is PVM
while [ -n "${1}" ]; do
         case "${1}" in
            -h | -H | -help     | --help ) 
                      PrintHelp;;
            -v | -V | -version  | --version ) 
                      RunArgument -v;;
            -c | -C | -check    | --check ) 
                      RunArgument -c;;
            -l | -L | -lockcode | --lockcode ) ${PQS_ROOT}/pqs.x -l; exit 0;;
            -f | -F | -m | -M | -machine | --machine | -machinefile | --machinefile ) 
                      if [ -z "${2}" ]; then 
                              PrintHelp;
                      fi
                      MFILE="${2}"; 
                      shift; 
                      shift;;
            -pvm  | -PVM | --pvm | --PVM ) P_TYPE=1; shift;;
            -mpi  | -MPI | --mpi | --MPI ) P_TYPE=2; shift;;
            -mpi1 | -MPI1 | --mpi1 | --MPI1 ) P_TYPE=2; shift;;
            -mpi2 | -MPI2 | --mpi2 | --MPI2 ) P_TYPE=3; shift;;
            * ) 
                      if [ -z "${one}" ]; then
                          one="${1}";
                      elif [ -z "${two}" ]; then
                              two="${1}";
                      else
                          PrintHelp;
                      fi
                      shift;;
         esac
done
#
# if there are two arguments, the second must be 
# un unsigned integer number
#
if [ -n "${two}" ]; then
        if [ -n "${two//[[:digit:]]}" ]; then
                PrintHelp;
        fi
fi
#
# set number of processes
#
NPROCS=1
if [ -n "${two}" ] && [ ${two} -gt 1 ]; then
        ((NPROCS= ${two} + 1))
fi
GetJobName "${one}"
GetInputName "$jobname"
#
# store the old output file, if it exists
#
if [ -e "${jobname}.out" ]; then
        cat "${jobname}".out >> "${jobname}".old
        rm -f "${jobname}".out;
fi
#
# run the job
#
if [ ${NPROCS} -lt 2 ]; then
        echo "Running single processor job '${jobname}'"
        RunSerial "${inpname}";
else
        if [ -n "${MFILE}" ]; then 
                # test if machine file exists
                if [ ! -r "${MFILE}" ]; then
                        echo
                        echo  "The machine file '${MFILE}' does not exist or is not readable."
                        echo
                        exit 1;
                fi
        fi
        if [ ${P_TYPE} -eq 1 ]; then
                echo "Running parallel job '${jobname}' with $((${NPROCS} -1)) slaves using PVM"
                RunPVM "${inpname}" ${NPROCS} "${MFILE}";
        elif [ ${P_TYPE} -eq 2 ]; then
                echo "Running parallel job '${jobname}' with $((${NPROCS} -1)) slaves using MPI-1"
                RunMPI1 "${inpname}" ${NPROCS} "${MFILE}";
        elif [ ${P_TYPE} -eq 3 ]; then
                echo "Running parallel job '${jobname}' with $((${NPROCS} -1)) slaves using MPI-2"
                RunMPI2 "${inpname}" ${NPROCS} "${MFILE}";
        else
                echo "ERROR: unknown parallel environment"
                exit 1
        fi
fi
#
# append the console messages to the output files
#
cat console-messages >> "${jobname}".out
cat console-messages >> "${jobname}".log
