#!/bin/bash
#
# $Id$
#
#
########################################################################
# for debug, uncomment line below
#set -xv
########################################################################
# options par defaut pour la commande make
########################################################################
dim="96x72x19"
physique=lmd
code=gcm
filtre=filtrez
grille=reg
couple=false
veget=false
chimie=false
parallel=none
paramem="par"
compil_mod=prod
io=ioipsl
LIBPREFIX=""
fcm_path=none
cosp=false

# guess a default 'arch'
arch="local" # start with assuming we're on a local machine with local arch file
## try to recognise machine and infer arch from it
machine=`hostname`
if [[ "$machine" == "brodie" ]]
then
  arch="SX8_BRODIE"
fi
if [[ "${machine:0:6}" == "vargas" ]]
then
  arch="PW6_VARGAS"
fi
if [[ "${machine:0:6}" == "ciclad" ]]
then
  arch="AMD64_CICLAD"
fi
if [[ "${machine:0:7}" == "platine" ]]
then
  arch="IA64_PLATINE"
fi
if [[ "${machine:0:6}" == "titane" ]]
then
  arch="X64_TITANE"
fi
if [[ "${machine:0:8}" == "mercure1" ]]
then
  arch="SX8_MERCURE"
fi
if [[ "${machine:0:8}" == "mercure2" ]]
then
  arch="SX9_MERCURE"
fi

LMDGCM=`pwd -P`
LIBFGCM=$LMDGCM/libf
LIBOGCM=$LMDGCM/libo
if [[ ! -d $LIBOGCM ]]
then
  # create the directory
  mkdir $LIBOGCM
  if [[ ! $? ]]
  then
  echo "Failed to create directory $LIBOGCM"
  exit
  fi
fi
COSP_PATH=$LMDGCM/.void_dir



localdir=`pwd -P`
########################################################################
#  Quelques initialisations de variables du shell.
########################################################################

CPP_KEY="" 
INCLUDE='-I$(LIBF)/grid -I$(LIBF)/bibio -I$(LIBF)/filtrez -I. '
LIB=""
adjnt=""
##COMPIL_FFLAGS="%PROD_FFLAGS"
PARA_FFLAGS=""
PARA_LD=""
EXT_SRC=""

########################################################################
# lecture des options
########################################################################

while (($# > 0))
  do
  case $1 in
      "-h") cat <<fin
Usage :
makelmdz [options] -arch nom_arch exec
[-h]                       : brief help
[-d [[IMx]JMx]LM]          : IM, JM, LM are the dimensions in x, y, z (default: $dim)
[-p PHYS]                  : set of physical parametrizations (in libf/phyPHYS), (default: lmd)
[-prod / -dev / -debug]    : compilation mode production (default) / developement / debug
[-c false/MPI1/MPI2]       : coupling with ocean model : MPI1/MPI2/false (default: false)
[-v false/orchidee2.0/orchidee1.9/true] : version of the vegetation model to include (default: false)
          false       : no vegetation model
          orchidee2.0 : compile using ORCHIDEE 2.0 (or more recent version)
          orchidee1.9 : compile using ORCHIDEE up to the version including OpenMP in ORCHIDEE : tag 1.9-1.9.5(version AR5)-1.9.6
          true        : (obsolete; for backward compatibility) use ORCHIDEE tag 1.9-1.9.6
[-chimie INCA/false]       : with INCA chemistry model or without (default: false)
[-parallel none/mpi/omp/mpi_omp] : parallelism (default: none) : mpi, openmp or mixted mpi_openmp
[-g GRI]                   : grid configuration in dyn3d/GRI_xy.h  (default: reg, inclues a zoom)
[-io IO]                   : Input/Output library (default: ioipsl)
[-include INCLUDES]        : extra include path to add
[-cpp CPP_KEY]             : additional preprocessing definitions
[-adjnt]                   : adjoint model, not operational ...
[-mem]                     : reduced memory dynamics (if in parallel mode)
[-filtre NOMFILTRE]        : use filtre from libf/NOMFILTRE (default: filtrez)
[-link LINKS]              : additional links with other libraries
[-fcm_path path]           : path to the fcm tool (default: tools/fcm/bin)
[-ext_src path]            : path to an additional set of routines to compile with the model
 -arch nom_arch            : target architecture 
 exec                      : executable to build
fin
	  exit;;
      "-d")
	  dim=$2 ; shift ; shift ;;
      
      "-p")
	  physique="$2" ;  shift ; shift ;;

      "-g")
	  grille="$2" ; shift ; shift ;;

      "-c")
	  couple="$2" ; shift ; shift ;;

      "-prod")
	  compil_mod="prod" ; shift ;;

      "-dev")
	  compil_mod="dev" ; shift ;;

      "-debug")
	  compil_mod="debug" ; shift ;;

      "-io")
	  io="$2" ; shift ; shift ;;

      "-v")
	  veget="$2" ; shift ; shift ;;

      "-chimie")
	  chimie="$2" ; shift ; shift ;;

      "-parallel")
	  parallel="$2" ; shift ; shift ;;
      
      "-include")
	  INCLUDE="$INCLUDE -I$2" ; shift ; shift ;;

      "-cpp")
	  CPP_KEY="$CPP_KEY $2" ; shift ; shift ;;

      "-adjnt")
	  echo "not operational ... work to be done here ";exit
	  opt_dep="$opt_dep adjnt" ; adjnt="-ladjnt -ldyn3d "
	  optim="$optim -Dadj" ; shift ;;

      "-cosp")
          cosp="$2" ; shift ; shift ;;
      
      "-mem")
          paramem="mem" ; shift ;;

      "-filtre")
	  filtre=$2 ; shift ; shift ;;

      "-link")
	  LIB="$LIB $2" ; shift ; shift ;;

      "-fcm_path")
	  fcm_path=$2 ; shift ; shift ;;

      "-ext_src")
	  EXT_SRC=$2 ; shift ; shift ;;

      "-arch")
	  arch=$2 ; shift ; shift ;;

      *)
	  code="$1" ; shift ;;
  esac
done

###############################################################
# lecture des chemins propres  l'architecture de la machine #
###############################################################
rm -f .void_file
echo > .void_file
rm -rf .void_dir
mkdir .void_dir
rm -f arch.path
if [[ -r arch/arch-${arch}.path ]]
then
  ln -s arch/arch-${arch}.path ./arch.path
  source arch.path
else
  echo "Error: missing arch/arch-${arch}.path file !"
  exit
fi
rm -f arch.fcm
if [[ -r arch/arch-${arch}.fcm ]]
then
  ln -s arch/arch-${arch}.fcm arch.fcm
else
  echo "Error: missing arch/arch-${arch}.fcm file !"
  exit
fi
########################################################################
# Definition des clefs CPP, des chemins des includes et modules
#  et des libraries
########################################################################

# basic compile flags from arch.fcm file
archfileline=$( grep -i '^%BASE_FFLAGS' arch.fcm )
COMPIL_FFLAGS=$( echo ${archfileline##%BASE_FFLAGS} )

# other compile flags, depending on compilation mode
if [[ "$compil_mod" == "prod" ]]
then
## read COMPIL_FFLAGS from arch.fcm file
  archfileline=$( grep -i '^%PROD_FFLAGS' arch.fcm )
  archfileopt=$( echo ${archfileline##%PROD_FFLAGS} )
  COMPIL_FFLAGS="${COMPIL_FFLAGS} ${archfileopt}"
elif [[ "$compil_mod" == "dev" ]]
then
## read %DEV_FFLAGS from arch.fcm file
  archfileline=$( grep -i '^%DEV_FFLAGS' arch.fcm )
  archfileopt=$( echo ${archfileline##%DEV_FFLAGS} )
  COMPIL_FFLAGS="${COMPIL_FFLAGS} ${archfileopt}"
elif [[ "$compil_mod" == "debug" ]]
then
## read %DEBUG_FFLAGS from arch.fcm file
  archfileline=$( grep -i '^%DEBUG_FFLAGS' arch.fcm )
  archfileopt=$( echo ${archfileline##%DEBUG_FFLAGS} )
  COMPIL_FFLAGS="${COMPIL_FFLAGS} ${archfileopt}"
fi

# add CPP_KEY defined in arch.fcm file
archfileline=$( grep -i '^%FPP_DEF' arch.fcm )
archfileopt=$( echo ${archfileline##%FPP_DEF} )
CPP_KEY="$CPP_KEY ${archfileopt}"

# get compiler name from arch.fcm file
archfileline=$( grep -i '^%COMPILER' arch.fcm )
fcompiler=$( echo ${archfileline##%COMPILER} )

# get linker name from arch.fcm file
archfileline=$( grep -i '^%LINK' arch.fcm )
linker=$( echo ${archfileline##%LINK} )

# get ar command from arch.fcm file
archfileline=$( grep -i '^%AR' arch.fcm )
arcommand=$( echo ${archfileline##%AR} )

# get make utility from arch.fcm file
archfileline=$( grep -i '^%MAKE' arch.fcm )
makecommand=$( echo ${archfileline##%MAKE} )

# get basic libraries to link with arch.fcm file
archfileline=$( grep -i '^%BASE_LD' arch.fcm )
archfileopt=$( echo ${archfileline##%BASE_LD} )
LIB="$LIB  ${archfileopt}"

if [[ "$physique" != "nophys" ]]
then
   #We'll use some physics
   CPP_KEY="$CPP_KEY CPP_PHYS"
   if [[ "${physique:0:3}" == "lmd" ]]
   then
   #For lmd physics, default planet type is Earth
   CPP_KEY="$CPP_KEY CPP_EARTH"
   fi
fi

if [[ "$chimie" == "INCA" ]]
then
   CPP_KEY="$CPP_KEY INCA"
   INCLUDE="$INCLUDE -I${INCA_INCDIR}"
   LIB="$LIB -L${INCA_LIBDIR} -lchimie"
   libchimie=" -L${INCA_LIBDIR} -lchimie"
fi

if [[ "$couple" != "false" ]]
then
   CPP_KEY="$CPP_KEY CPP_COUPLE"
   INCLUDE="$INCLUDE -I${OASIS_INCDIR}"
   LIB="$LIB -L${OASIS_LIBDIR} -lpsmile.${couple} -lmpp_io"
fi

if [[ "$parallel" == "none" ]]
then
  FLAG_PARA=''
else
  FLAG_PARA="$paramem"
fi

if [[ "$parallel" == "mpi" ]]
then
   CPP_KEY="$CPP_KEY CPP_PARA CPP_MPI"
  # MPI additional compilation options 
  archfileline=$( grep -i '^%MPI_FFLAGS' arch.fcm )
  PARA_FFLAGS=$( echo ${archfileline##%MPI_FFLAGS} )
  # MPI additional links
  archfileline=$( grep -i '^%MPI_LD' arch.fcm )
  PARA_LD=$( echo ${archfileline##%MPI_LD} )
elif [[ "$parallel" == "omp" ]]
then
   CPP_KEY="$CPP_KEY CPP_PARA CPP_OMP"
  # OMP additional compilation options 
  archfileline=$( grep -i '^%OMP_FFLAGS' arch.fcm )
  PARA_FFLAGS=$( echo ${archfileline##%OMP_FFLAGS} )
  # OMP additional links
  archfileline=$( grep -i '^%OMP_LD' arch.fcm )
  PARA_LD=$( echo ${archfileline##%OMP_LD} )
elif [[ "$parallel" == "mpi_omp" ]]
then
   CPP_KEY="$CPP_KEY CPP_PARA CPP_MPI CPP_OMP"
  # MPI additional compilation options 
  archfileline=$( grep -i '^%MPI_FFLAGS' arch.fcm )
  PARA_FFLAGS=$( echo ${archfileline##%MPI_FFLAGS} )
  # OMP additional compilation options 
  archfileline=$( grep -i '^%OMP_FFLAGS' arch.fcm )
  PARA_FFLAGS="${PARA_FFLAGS} "$( echo $archfileopt ${archfileline##%OMP_FFLAGS} )
  # MPI additional links
  archfileline=$( grep -i '^%MPI_LD' arch.fcm )
  PARA_LD=$( echo ${archfileline##%MPI_LD} )
  # OMP additional links
  archfileline=$( grep -i '^%OMP_LD' arch.fcm )
  PARA_LD="${PARA_LD} "$( echo $archfileopt ${archfileline##%OMP_LD} )
fi

if [[ ( "$parallel" == "omp" || "$parallel" == "mpi_omp" ) \
   && "$compil_mod" == "debug" ]]
then
    echo "Usually, parallelization with OpenMP requires some optimization."
    echo "We suggest switching to \"-dev\"."
fi


#==============================================================================
if [ "$veget" = "true" -o "$veget" = "orchidee1.9" -o "$veget" = "orchidee2.0" ]
then

   INCLUDE="${INCLUDE} -I${ORCH_INCDIR}"
   CPP_KEY="$CPP_KEY CPP_VEGET"
# temporary, for Orchidee versions 1.9.* (before openmp activation)
   if [[ "$veget" == "orchidee1.9" ]] ; then
      CPP_KEY="$CPP_KEY ORCHIDEE_NOOPENMP"
   fi
   if [[ "$veget" == "orchidee2.0" ]] ; then
      orch_libs=orchidee
   else
      orch_libs="sechiba parameters stomate parallel orglob"
   fi
   LIB="${LIB} -L${ORCH_LIBDIR}"
   for lib in ${orch_libs} ; do
      if [ -f ${ORCH_LIBDIR}/lib${LIBPREFIX}$lib.a ] ; then
         LIB="${LIB} -l${LIBPREFIX}$lib "
      fi
   done
elif [[ "$veget" != "false" ]] ; then
   echo "Option -v $veget does not exist"
   echo "Use ./makelmdz -h for more information"
   exit 
fi

#===============================================================================
if [[ $io == ioipsl ]]
then
   CPP_KEY="$CPP_KEY CPP_IOIPSL"
   INCLUDE="$INCLUDE -I${IOIPSL_INCDIR}"
   LIB="$LIB -L${IOIPSL_LIBDIR} -l${LIBPREFIX}ioipsl"
fi

if [[ "$cosp" == "true" ]]
then
   CPP_KEY="$CPP_KEY CPP_COSP"
   COSP_PATH="$LIBFGCM/cosp"
#   LIB="${LIB} -l${LIBPREFIX}cosp"
   opt_dep="$opt_dep cosp"
   lcosp="-l${LIBPREFIX}cosp"
   INCLUDE="$INCLUDE"' -I$(LIBF)/cosp'
fi

INCLUDE="$INCLUDE ${NETCDF_INCDIR}"
LIB="$LIB ${NETCDF_LIBDIR}"

########################################################################
# calcul du nombre de dimensions
########################################################################


dim_full=$dim
dim=`echo $dim | sed -e 's/[^0-9]/ /g'` 
set $dim
dimc=$#
echo calcul de la dimension
echo dim $dim
echo dimc $dimc


########################################################################
# Gestion des dimensions du modele.
# on cree ou remplace le fichier des dimensions
########################################################################

cd $LIBFGCM/grid
if [[ -f dimensions.h ]]
then
  echo 'ATTENTION: vous etes sans doute en train de compiler le modele par ailleurs'
  echo "Attendez que la premiere compilation soit terminee pour relancer la suivante."
  echo "Si vous etes sur que vous ne compilez pas le modele par ailleurs,"
  echo  vous pouvez continuer en repondant oui.
  echo "Voulez-vous vraiment continuer?"
  echo ""
  echo "WARNING: you are probably already compiling the model somewhere else."
  echo "Wait until the first compilation is finished before launching this one."
  echo "If you are sure that you are not compiling elsewhere, just answer "
  echo "yes (or 'oui') to the question below to proceed."
  echo "Do you wish to continue?"
  read reponse
  if [[ $reponse == "oui" || $reponse == "yes" ]]
  then
    \rm -f $LIBFGCM/grid/dimensions.h
  else
    exit
  fi
fi


cd $LIBFGCM/grid/dimension
./makdim $dim
cat $LIBFGCM/grid/dimensions.h
cd $LMDGCM


########################################################################
# Differentes dynamiques (3d, 2d, 1d)
########################################################################

if (( $dimc == 3 )) ; then
   cd $LIBFGCM/grid
   \rm fxyprim.h
   cp -p fxy_${grille}.h fxyprim.h
   filtre="FILTRE=$filtre"
   INCLUDE="$INCLUDE "'-I$(LIBF)/dyn3d${FLAG_PARA} '
elif (( $dimc == 2 )) ; then
   filtre="FILTRE= L_FILTRE= "
   INCLUDE="$INCLUDE "'-I$(LIBF)/dyn2d'
elif (( $dimc == 1 )) ; then
   filtre="L_DYN= DYN= FILTRE= L_FILTRE= DIRMAIN=phy$physique "
   INCLUDE="$INCLUDE "'-I$(LIBF)/dyn3d' # Pas tres propre
else
   echo Dimension dimc=$dimc pas prevu ; exit
fi

######################################################################
# Creation du suffixe de la configuration
######################################################################

SUFF_NAME=_${dim_full}
SUFF_NAME=${SUFF_NAME}_phy${physique}

if [[ "$parallel" != "none" ]]
then
  SUFF_NAME=${SUFF_NAME}_para
  DYN=dyn${dimc}d${paramem}
  if [[ "$paramem" == "mem" ]]
  then
   SUFF_NAME=${SUFF_NAME}_${paramem}
  fi
else
  SUFF_NAME=${SUFF_NAME}_seq
  DYN=dyn${dimc}d
fi

if [[ $veget != "false" ]]
then
  SUFF_NAME=${SUFF_NAME}_orch
fi

if [[ $couple != "false" ]]
then
  SUFF_NAME=${SUFF_NAME}_couple
fi

if [[ $chimie == "INCA" ]]
then
  SUFF_NAME=${SUFF_NAME}_inca
fi

cd $LMDGCM


########################################################################
#  Avant de lancer le make, on recree le makefile si necessaire
########################################################################
########################################################################
# c'est a dire dans 3 cas:
# 1. si la liste des fichiers .F et .h a ete modifiee depuis la
#    derniere creation du makefile
# 2. si le fichier contenant cette liste "liste_des_sources"
#    n'existe pas.
# 3. Si le makefile n'existe pas.
########################################################################
cd $LMDGCM

find libf -name '*.[Fh]' -print > tmp77
find libf -name '*.[Fh]' -exec egrep -i " *use *ioipsl" {} \; -print > tmp90
find libf -name '*.[Fh90]' -print >> tmp90

if [[ ! ( -r makefile ) || ! ( -r liste_des_sources_f90 ) || ! ( -r liste_des_sources_f77 ) || ` diff tmp77 liste_des_sources_f77 | wc -w ` -ne 0 || ` diff tmp90 liste_des_sources_f90 | wc -w ` -ne 0 ]]
then
  echo "les fichiers suivants ont ete crees ou detruits"
  echo "ou les fichiers suivants sont passes ou ne sont plus en Fortran 90"
  diff liste_des_sources_f77 tmp77
  diff liste_des_sources_f90 tmp90
  \cp -f tmp77 liste_des_sources_f77
  \cp -f tmp90 liste_des_sources_f90
  echo "on recree le makefile"
  ./create_make_gcm > tmp 
  \mv -f tmp makefile
  echo "Nouveau makefile cree"
fi

#################################################################
# Preparation de l'execution de la comande make
#################################################################

source_code=${code}.F
if [[ -r $LMDGCM/libf/dyn${dimc}d${FLAG_PARA}/${code}.F90 ]]
then
  source_code=${code}.F90
fi

# library directory name:
nomlib=`echo ${arch}_${physique}_${dim_full}_${grille}_${compil_mod}_parall${parallel}_${CPP_KEY}_${FLAG_PARA} | sed -e 's/ //g' -e 's/-//g ' | sed -e 's/CPP_//g'`
echo $nomlib

if [[ ! -d "${LIBOGCM}/${nomlib}" ]]
then
  mkdir ${LIBOGCM}/${nomlib}
  # check we indeed managed to create the directory
  if [[ ! $? ]]
  then
    echo "Error: could not create directory ${LIBOGCM}/${nomlib}"
    exit
  fi
fi

# where module files are created 
mod_loc_dir=$localdir

if [[ "$physique" != "nophys" ]]
then
  INCLUDE="$INCLUDE"' -I$(LIBF)/phy'"$physique"
fi
INCLUDE="$INCLUDE"' -I'${LIBOGCM}/${nomlib}

# ranlib utility (check it exists or else default to ls)
if [[ `which ranlib > /dev/null 2>&1 ; echo $?` -eq 0 ]]
then
  ranlib="ranlib"
else
  ranlib="ls"
fi

# add CPP keys to COMPIL_FLAGS
# (but first add -D before all CPP_KEY items)
cpp_definitions=`echo $CPP_KEY | sed -e 's/[A-Za-z_=0-9]*/-D&/g'`
# (but add a -WF,-D before all CPP_KEY items) => for xlf on Vargas
if [[ "${fcompiler:0:3}" == "xlf" ]]
then
cpp_definitions=`echo $CPP_KEY | sed -e 's/[A-Za-z_=0-9]*/-WF,-D&/g'`
fi
COMPIL_FFLAGS="${COMPIL_FFLAGS} ${cpp_definitions}"

#################################################################
# Execution du make
#################################################################
echo $makecommand RANLIB=$ranlib -f $LMDGCM/makefile \
OPTION_DEP="$opt_dep" OPTION_LINK="$LIB ${PARA_LD}" \
OPTIM90="${COMPIL_FFLAGS} ${PARA_FFLAGS}" \
OPTIMTRU90="${COMPIL_FFLAGS} ${PARA_FFLAGS}" \
OPTIM="${COMPIL_FFLAGS} ${PARA_FFLAGS}" \
INCLUDE="$INCLUDE" \
$filtre \
LIBO=${LIBOGCM}/${nomlib} \
"PHYS=$physique" \
DIM=$dimc \
FLAG_PARA=$FLAG_PARA \
L_ADJNT=$adjnt \
L_COSP="$lcosp" \
L_CHIMIE="$libchimie" \
LOCAL_DIR="$localdir"  \
F77="$fcompiler" \
F90="$fcompiler" \
OPLINK="$LIB" \
LINK="$linker" \
GCM="$LMDGCM" \
MOD_LOC_DIR=$mod_loc_dir \
MOD_SUFFIX="mod" \
AR=$arcommand \
SOURCE=$source_code \
PROG=$code

$makecommand RANLIB=$ranlib -f $LMDGCM/makefile \
OPTION_DEP="$opt_dep" OPTION_LINK="$LIB ${PARA_LD}" \
OPTIM90="${COMPIL_FFLAGS} ${PARA_FFLAGS}" \
OPTIMTRU90="${COMPIL_FFLAGS} ${PARA_FFLAGS}" \
OPTIM="${COMPIL_FFLAGS} ${PARA_FFLAGS}" \
INCLUDE="$INCLUDE" \
$filtre \
LIBO=${LIBOGCM}/${nomlib} \
"PHYS=$physique" \
DIM=$dimc \
FLAG_PARA=$FLAG_PARA \
L_ADJNT=$adjnt \
L_COSP="$lcosp" \
L_CHIMIE="$libchimie" \
LOCAL_DIR="$localdir"  \
F77="$fcompiler" \
F90="$fcompiler" \
OPLINK="$LIB" \
LINK="$linker" \
GCM="$LMDGCM" \
MOD_LOC_DIR=$mod_loc_dir \
MOD_SUFFIX="mod" \
AR=$arcommand \
SOURCE=$source_code \
PROG=$code


if [[ -r $LIBFGCM/grid/dimensions.h ]]
then
  # Cleanup: remove dimension.h file
  \rm -f $LIBFGCM/grid/dimensions.h
fi
