#!/bin/bash

#=============================================================================
#  F. Hourdin : 2022/05/03
#
#  Objet :
#  -----
#  Script préparant les programes pour rejouer (replay) une paramétrisation
#  ou un morceau de paramétriation.
#
#
#  Applicabilité :
#  ---------------
#  Est fait pour rejouer des paramétisation de LMDZ organisées comme
#    des calcul sur des successions de colonnes indépendantes (boucle
#    interne en $klon) de $klev niveaux verticaux.
#  Demande que la paramétrisation répondent aux règles de codage suivantes :
#  1) Les routines de calcul et les routines ou fonction qu'elles appellent
#     n'ont que deux interfaces : A) les arguments d'entrée
#                                 B) le use d'un unique module
#     Entre autre, les dimensions de la paramétrisation sont passés
#     en argument, ce qui permet une allocation dynamique implicite
#     de toutes les variables.
#  2) le module d'initialisation doit lui même être initialisé par 
#     une unique routine pilotée entièrement par ses arguments.
#  3) Toutes les variables d'interface doivent être déclarées intent in
#     ou intent out.
#  On appelera la paramétriation "param" et l'intialisation "param_ini"
#     mais les noms de fichiers sont en argument dans le script.
#
#
#  Principe :
#  ----------
#  Dans une première simulation, on écrit dans un fichier binaire toutes
#  les variables "intent in" de la routine d'initialisation et de la routine
#  de calcul.
#
#
#  En pratique :
#  -------------
#
#  Le script est commandé par les variables suivantes
#   param=wake             # nom de la subroutine (à l'interireur du fichier)
#   paramini=wake_ini  # nom de la subroutine d'intialisation
#   inimod= # nom du module contenant $param_ini
#   klon=klon ; klev=klev  # nom des dimensions horiz; vert utilisée
#
#  Le fichier ${paramfile} contenant $param est detecté automatiquement
#  Le script crée 4 fichiers
#  * dump_param.h          : écriture de l'interface "in" de param (dump_param.bin fort.82)
#  * call_param_replay.F90 : sous programme d'appelle en boucle à la param
#  * dump_ini_module.F90   : écriture de l'interface "in" de param_ini
#  * get_ini_module.F90    : lecture de l'interface "in" de param_ini
#                dans ${param_ini}_mod.bin.
#  Par ailleurs, un programme replay1d a été ajouté dans phylmd/dyn1d
#        qui appelle call_param_replay
#  Le script ajoute par ailleurs quelques lignes dans ${paramfile} et
#        ${param_ini}.F90
#  replay_clean.sh élimine toutes les lignes ajoutées 
#
#
#  A travailler :
#  --------------
#  * détecter automatiquement le fichier contenant l'intialisation
#  * détecter automatiquement les dimensions
#  * avoir un moyen de vérifier si les variables intent in et out sont
#    bien les bonnes.
#  * test en 3D.
#  * Initialisation plus simple de la routine getin_p
#  * Des choix sur la facon de controler l'initialisation et le pb des getin
#  * Modifier la compilation du 1D pour pouvoir compiler lmdz1d et replay1d
#  * Comprendre pourquoi le replay de wake ne semble pas donner une convegence
#      numerique avec la version initiale
#  * L'identification des variables intent in & out pour l'ecriture dans .h
#     va sans doute foirer si plusieurs routines dans le même fichier.
#     On pourrait d'ailleurs sortir toutes les variables locales également.
#     En option par exemple
#  * Corriger create_make_gcm (pour le main) et makelmdz (pour les checks
#     sur la necessitee d'appeler create_make_gcm)
#  * Mettre en option le fait de pouvoir sortir non seulement toutes
#     les variables d'interface mais même toutes les variables internes.
#
#=============================================================================

param=$1
case $param in
   thermcell_main|thermcell_plume_6A|thermcell_env|thermcell_height|thermcell_dry|\
      thermcell_closure|thermcell_height|thermcell_dq|thermcell_flux2|thermcell_down) \
      paramini=thermcell_ini ; inimod=thermcell_ini_mod ; klon=ngrid ; klev=nlay ;;
   wake) paramini=wake_ini ; inimod=wake_ini_mod ; klon=klon ; klev=klev ;;
   *) echo Cas non prevu ; exit
esac

replay_comment="replay automatic include"

#-----------------------------------------------------------------------------
# Transformer l'entete d'une subroutine en un call
#-----------------------------------------------------------------------------

function get_subroutine_arg(){
   cat $1 | tr '[A-Z]' '[a-z]' > tmp
   line1=`sed -n -e '/subrou.*(/=' tmp | head -1 `
   line2=`tail -n +$line1 tmp | sed -n -e '/)/=' | head -1`
   tail -n +$line1 tmp | sed -n -e 1,${line2}p
}

#-----------------------------------------------------------------------------
function extract_subroutine(){
#-----------------------------------------------------------------------------
   # $1 nom de la subroutine
   # $2 nom du fichier
   # cat $2 | tr '[A-Z]' '[a-z]' > tmp
   cpp $2 | tr '[A-Z]' '[a-z]' > tmp
   name_min=`echo $1 | tr '[A-Z]' '[a-z]'`
   line1=`sed -n -e "/subrou.*${name_min}.*(/=" tmp | head -1 `
   tail -n +$line1 tmp > tmp2
   line2=`sed -n -e "/[Rr][Ee][Tt][Uu][Rr][Nn]/=" tmp2 | head -1`
   head -$line2 tmp2
   \rm -f tmp tmp2
}

#-----------------------------------------------------------------------------
function get_param_file(){
#-----------------------------------------------------------------------------
  grep -i "subro.* $1[\ (]" *.F90 | sed -e 's/ //g' | grep "$1(" | cut -d: -f1
}

#-----------------------------------------------------------------------------
# Identification et passage à la casse du bas pour du fichier contenant la param
#-----------------------------------------------------------------------------

paramfile=`get_param_file $param`
echo La parametrisation $param est contenue dans le fichier $paramfile
if [ `echo ${paramfile} | wc -w` != 1 ] ; then exit ; fi
extract_subroutine $param $paramfile > input

#-----------------------------------------------------------------------------
# Liste des variables d'intent in pour stokage
#-----------------------------------------------------------------------------

varin0=`grep inten.*.in input | sed -e '/\!.*$/d' | cut -d: -f3 | sed -e 's/,/ /g'`
echo varin0 $varin0
varin=`echo $varin0 | sed -e 's/ /,/g' -e "s/,,,/,/g" -e "s/,,/,/g"`
echo varin $varin
output=full # Attention, l'option full ne marche pas a cause de tableaux locaux undef
nvar0D=0 ; nvar1D=0 ; nvar2D=0
case $output in
   light) search_str='real.*intent' ;;
   full) search_str='real'
esac
var_1D=`grep -i "$search_str" input | grep $klon | sed -e 's/!.*$//' -e /$klev/d | cut -d: -f3 | sed -e 's/,/ /g'`
var_2D=`grep -i "$search_str" input | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
echo varin  : $varin
echo var_1D : $var_1D
echo var_2D : $var_2D

#-----------------------------------------------------------------------------
# Ecriture de la routine d'appel a la parametrisation en mode replay
#-----------------------------------------------------------------------------

cat > call_param_replay.F90 <<eod
subroutine call_param_replay($klon,$klev)
IMPLICIT NONE
integer ifin
eod
head -200 input | grep intent | sed -e 's/ //g' -e 's/,intent(.*[nt])//'>> call_param_replay.F90
cat >> call_param_replay.F90 <<eod
read(82,iostat=ifin) $varin
if (ifin<0) stop "Fin du fichier fort.82"
eod
get_subroutine_arg $paramfile | sed -e 's/subroutine/call/' >> call_param_replay.F90
echo return >> call_param_replay.F90
echo end >> call_param_replay.F90

#-----------------------------------------------------------------------------
# Creation d'un .h d'ecriture de toutes les variables intent in & out
#-----------------------------------------------------------------------------

paraminc=dump_param.h
cat > $paraminc <<eod
   write(81) $varin
eod
for var in $var_1D ; do
echo "call iotd_ecrit_seq('"$var"',1,'"$var"',' ',"$var")" >> $paraminc
done
for var in $var_2D ; do
echo "call iotd_ecrit_seq('"$var"',"$klev",'"$var"',' ',"$var")" >> $paraminc
done
  
#-----------------------------------------------------------------------------
# dump_ini_module gere l'ecriture des variables d'interface de l'intialisation
# du module en mode replay
#-----------------------------------------------------------------------------

varinmod=`grep -i 'intent.in' $inimod.F90 | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
varinmodv=`echo $varinmod | sed -e 's/ /,/g'`
cat > dump_ini.h <<eod
open(90,file='$inimod.bin',form='unformatted')
write(90) $varinmodv
close(90)
eod


#-----------------------------------------------------------------------------
# get_ini_module gere l'initialisation du module en mode replay
#-----------------------------------------------------------------------------

cat > get_ini_module.F90 <<eod
subroutine get_ini_module
use $inimod
IMPLICIT NONE
eod
grep -i intent.in $inimod.F90  |  tr '[A-Z]' '[a-z]' | sed -e 's/,.*intent.i.*)//' >> get_ini_module.F90
cat >> get_ini_module.F90 <<eod
open(90,file='$inimod.bin',form='unformatted')
read(90) $varinmodv
close(90)
eod
get_subroutine_arg $inimod.F90 | sed -e 's/subroutine/call/' >> get_ini_module.F90
cat >> get_ini_module.F90 <<eod
return
end
eod

#-----------------------------------------------------------------------------
# On nettoye les inclusions précédente dans les fichiers .F90
#-----------------------------------------------------------------------------

for file in `grep "$replay_comment" *.F90 2> /dev/null | cut -d: -f1` ; do
   sed -i"" -e "/$replay_comment/d" $file
done
line=`sed -n -e "/CALL wake_ini/=" physiq_mod.F90 | head -1`
cp physiq_mod.F90 physiq_mod.$$
sed -i"" -e "${line}s/$/\n   CALL iophys_ini(pdtphys) ! $replay_comment\n   open(81,file='dump_param.bin',form='unformatted')  ! $replay_comment/" physiq_mod.F90


#-----------------------------------------------------------------------------
# Inclusion d'un include dans la parametrisation
#-----------------------------------------------------------------------------

line=`sed -n -e "/^.*[Rr][Ee][Tt][Uu][Rr][Nn].*$/=" $paramfile | head -1`
sed -i"" -e "${line}s/^.*$/   include \"$paraminc\" ! $replay_comment \n RETURN/" $paramfile

#-----------------------------------------------------------------------------
# Inclusion de l'ecriture de l'interface de l'initialisation
#-----------------------------------------------------------------------------

sed -i'' -e "s/^.*[Rr][Ee][Tt][Uu][Rr][Nn].*$/include \"dump_ini.h\" ! $replay_comment \n RETURN/" $inimod.F90

#\rm -f tmp input
