#!/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
compil_mod=prod
io=ioipsl
LIBPREFIX=""
fcm_path=none
cosp=false
dyn=""

# guess a default 'arch'
arch="g95" # start with assuming we're on a Linux/Unix machine with g95
## 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=""
ccompiler=""
OPTIMC=""
INCLUDEC=""

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

while (($# > 0))
  do
  case $1 in
      "-h") cat <<fin
manuel complet sur http://...
Usage :
makegcm [options] exec
[-h]                       : manuel abrege
[-d [[IMx]JMx]LM]          : IM, JM, LM sont les dims en x, y, z (def: $dim)
[-p PHYS]                  : compilation avec la physique libf/phyPHYS, (def: lmd)
[-prod / -dev / -debug]    : compilation en mode production (default) / developpement / debug .
[-c false/MPI1/MPI2]       : couple ocean : MPI1/MPI2/false (def: false)
[-v false/true]            : avec ou sans vegetation (def: false)
[-chimie INCA/false]       : avec ou sans modele de chimie INCA (def: false)
[-parallel none/mpi/omp/mpi_omp] : parallelisation (default: none) : mpi, openmp ou mixte mpi_openmp
[-g GRI]                   : conf. grille dans dyn3d/GRI_xy.h  (def: reg inclue un zoom)
[-io IO]                   : choix d une librairie I/O, experts (def: ioipsl)
[-include INCLUDES]        : variables supplementaires pour include
[-cpp CPP_KEY]             : cle cpp supplementaires
[-adjnt]                   : adjoint, a remettre en route ...
[-filtre NOMFILTRE]        : prend le filtre dans libf/NOMFILTRE (def: filtrez)
[-link LINKS]              : liens optionels avec d autres librairies
[-ext_src path]            : chemin d un repertoire source avec des sources externe a compiler avec le modele
[-arch nom_arch]           : nom de l architecture cible
 exec                      : executable genere
fin
	  exit;;
      "-d")
	  dim=$2 ; shift ; shift ;;
      
      "-O")
	  echo "option obsolete dans ce makegcm"
	  exit;;

      "-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 "option a reactiver ";exit
	  opt_dep="$opt_dep adjnt" ; adjnt="-ladjnt -ldyn3d "
	  optim="$optim -Dadj" ; shift ;;

      "-cosp")
          cosp="$2" ; shift ; 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
   CPP_KEY="$CPP_KEY CPP_PHYS"
fi

if [[ "$physique" == "lmd" ]]
then
   #Default planet type is Earth
   CPP_KEY="$CPP_KEY CPP_EARTH"
fi

######### CAS PARTICULIER CHIMIE TITAN
if [[ "$physique" == "titan" ]]
then
   INCLUDE="$INCLUDE"' -I$(LIBF)/chim'"$physique"
   LIB="$LIB -l${LIBPREFIX}chim$physique"
   opt_dep="$opt_dep chim$physique"
# get C compiler name and optim from arch.fcm file
   archfileline=$( grep -i '^%C_COMPILER' arch.fcm )
   ccompiler=$( echo ${archfileline##%C_COMPILER} )
   archfileline=$( grep -i '^%C_OPTIM' arch.fcm )
   coptim=$( echo ${archfileline##%C_OPTIM} )
   OPTIMC="$OPTIMC  ${coptim}"
   INCLUDEC='-I$(LIBF)/grid -I.'
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="par"
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" ]]
then
   CPP_KEY="$CPP_KEY CPP_VEGET"
   INCLUDE="${INCLUDE} -I${ORCH_INCDIR}"
   LIB="${LIB} -L${ORCH_LIBDIR} -l${LIBPREFIX}sechiba -l${LIBPREFIX}parameters -l${LIBPREFIX}stomate -l${LIBPREFIX}parallel -l${LIBPREFIX}orglob"
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/dimension
./makdim $dim
cat $LIBFGCM/grid/dimensions.h
cd $LMDGCM


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

dimension=`echo $dim | wc -w`
echo dimension $dimension

if (( $dimension == 3 ))
then
  cd $LIBFGCM/grid
  \rm fxyprim.h
  cp -p fxy_${grille}.h fxyprim.h
#else
#  echo "Probleme dans les dimensions de la dynamique !!"
#  echo "Non reactive pour l'instant !!!"
fi
if (( $dimension == 1 ))
then
  echo pas de dynamique
  dyn="DYN= L_DYN=-ldyn3d "
fi

######################################################################
# Gestion du filtre qui n'existe qu'en 3d.
######################################################################

if (( `expr $dimc \> 2` == 1 ))
then
   filtre="FILTRE=$filtre"
else
   filtre="FILTRE= L_FILTRE= "
fi
echo MACRO FILTRE $filtre

echo $dimc

######################################################################
# 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
else
  SUFF_NAME=${SUFF_NAME}_seq
fi

if [[ $veget == "true" ]]
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
######### CAS PARTICULIER CHIMIE TITAN
if [[ "$physique" == "titan" ]]
then 
  find libf -name '*.[ch]' -print > tmpC
fi
#########

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
######### CAS PARTICULIER CHIMIE TITAN
  if [[ "$physique" == "titan" ]]
  then 
  diff liste_des_sources_C tmpC
  \cp -f tmpC liste_des_sources_C
  fi
#########
  echo "on recree le makefile"
  ./create_make_gcm > tmp 
  \mv -f tmp makefile
  echo "Nouveau makefile cree"
######### CAS PARTICULIER CHIMIE TITAN
else if [[ "$physique" == "titan" ]]
 then
   if [[ ! ( -r liste_des_sources_C ) || ` diff tmpC liste_des_sources_C | wc -w ` -ne 0 ]]
   then
     diff liste_des_sources_C tmpC
     \cp -f tmpC liste_des_sources_C
     echo "on recree le makefile"
     ./create_make_gcm > tmp 
     \mv -f tmp makefile
     echo "Nouveau makefile cree"
   fi
 fi
#########
fi

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

# find code suffix and directory where code is located
if [[ -r $LMDGCM/libf/dyn${dimc}d${FLAG_PARA}/${code}.F ]]
then
  source_code=${code}.F
  code_dir=dyn${dimc}d${FLAG_PARA}
else
  if [[ -r $LMDGCM/libf/dyn${dimc}d${FLAG_PARA}/${code}.F90 ]]
  then
    source_code=${code}.F90
    code_dir=dyn${dimc}d${FLAG_PARA}
  else
    if [[ -r $LMDGCM/libf/phy${physique}/${code}.F ]]
    then
      source_code=${code}.F
      code_dir=phy${physique}
    else
      # last possibility:
      if [[ -r $LMDGCM/libf/phy${physique}/${code}.F90 ]]
      then
        source_code=${code}.F90
        code_dir=phy${physique}
      else
        echo "Error: cannot find ${code}.F[90]"
        echo " neither in dyn${dimc}d${FLAG_PARA} nor in phy${physique}"
        exit
      fi
    fi
  fi
fi

# library directory name:
if [[ "$parallel" == "none" ]]
then 
  nomlib=${arch}_${physique}_${dim_full}_${grille}_${compil_mod}
else
  nomlib=${arch}_${physique}_${dim_full}_${grille}_${compil_mod}_${FLAG_PARA}
fi

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
if (( $dimension == 1 ))
then
 INCLUDE="$INCLUDE"' -I$(LIBF)/dyn3d -I'${LIBOGCM}/${nomlib}
else
 INCLUDE="$INCLUDE"' -I$(LIBF)/dyn'${dimc}'d'$FLAG_PARA' -I'${LIBOGCM}/${nomlib}
fi

# 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}" \
OPTIMC="$optimc" \
INCLUDE="$INCLUDE" \
INCLUDEC="$includec" \
$filtre \
$dyn \
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" \
CCC="$ccompiler" \
OPLINK="$LIB" \
LINK="$linker" \
GCM="$LMDGCM" \
MOD_LOC_DIR=$mod_loc_dir \
MOD_SUFFIX="mod" \
AR=$arcommand \
DIRMAIN=$code_dir \
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}" \
OPTIMC="$optimc" \
INCLUDE="$INCLUDE" \
INCLUDEC="$includec" \
$filtre \
$dyn \
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" \
CCC="$ccompiler" \
OPLINK="$LIB" \
LINK="$linker" \
GCM="$LMDGCM" \
MOD_LOC_DIR=$mod_loc_dir \
MOD_SUFFIX="mod" \
AR=$arcommand \
DIRMAIN=$code_dir \
SOURCE=$source_code \
PROG=$code

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