source: BOL/Replay/replay_equip.sh @ 4358

Last change on this file since 4358 was 4353, checked in by fhourdin, 2 years ago

Correction de l'otpion inout

File size: 18.1 KB
RevLine 
[4337]1#!/bin/bash
2
3#set -vx
4
5#=============================================================================
6#  F. Hourdin : 2022/05/03
7#
8#  Objet :
9#  -----
10#  Script préparant les programes pour rejouer (replay) une paramétrisation
11#  ou un morceau de paramétriation.
12#
13#
14#  Applicabilité :
15#  ---------------
16#  Est fait pour rejouer des paramétisation de LMDZ organisées comme
17#    des calcul sur des successions de colonnes indépendantes (boucle
18#    interne en $klon) de $klev niveaux verticaux.
19#  Demande que la paramétrisation répondent aux règles de codage suivantes :
20#  1) Les routines de calcul et les routines ou fonctions qu'elles appellent
21#     n'ont que deux interfaces : A) les arguments d'entrée
22#                                 B) le use d'un unique module
23#     Entre autre, les dimensions de la paramétrisation sont passés
24#     en argument, ce qui permet une allocation dynamique implicite
25#     de toutes les variables.
26#  2) le module d'initialisation doit lui même être initialisé par
27#     une unique routine pilotée entièrement par ses arguments.
28#  3) Toutes les variables d'interface doivent être déclarées intent in
29#     out, ou inout
30#  On appelera la paramétriation "param" et l'intialisation "param_ini"
31#     mais les noms de fichiers sont en argument dans le script.
32#
33#
34#  Principe :
35#  ----------
36#  Dans une première simulation, on écrit dans un fichier binaire toutes
37#  les variables "intent in/inout" de la routine d'initialisation et de la routine
38#  de calcul.
39#
40#
41#  En pratique :
42#  -------------
43#
44#  Le script a comme argument le nom de la routine à traiter, nommée $param
45#   Des correpspondances en déduisent :
46#   paramini=wake_ini  # nom de la subroutine d'intialisation
47#   inimod= # nom du module contenant $param_ini
48#   klon=klon ; klev=klev  # nom des dimensions horiz; vert utilisée
49#
50#  Le fichier ${paramfile} contenant $param est detecté automatiquement
51#  Le script crée 5 fichiers
52#  * dump_param1.h          : écriture de l'interface "in" de param (dump_param.bin fort.82)
53#  * dump_param2.h          : écriture des sorties de la routines dans phys.nc
54#  * call_param_replay.F90 : sous programme d'appelle en boucle à la param
55#  * dump_ini_module.F90   : écriture de l'interface "in" de param_ini
56#  * get_ini_module.F90    : lecture de l'interface "in" de param_ini
57#                dans ${param_ini}_mod.bin.
58#  Par ailleurs, un programme replay1d a été ajouté dans phylmd/dyn1d
59#        qui appelle call_param_replay
60#  Le script ajoute par ailleurs quelques lignes dans ${paramfile} et
61#        ${param_ini}.F90
62#  replay_clean.sh élimine toutes les lignes ajoutées
63#
64#
65#  A travailler :
66#  --------------
67#  * détecter automatiquement le fichier contenant l'intialisation
68#  * détecter automatiquement les dimensions
69#  * avoir un moyen de vérifier si les variables intent in et out sont
70#    bien les bonnes.
71#  * Initialisation plus simple de la routine getin_p
72#  * Des choix sur la facon de controler l'initialisation et le pb des getin
73#
74#=============================================================================
75
[4346]76#-----------------------------------------------------------------------------
77# Reading rguments
78#-----------------------------------------------------------------------------
79nconly=false
[4347]80where=-before_return
81
[4346]82if [ $# = 0 ] ; then $0 -h ; exit ; fi
83while (($# > 0))
84   do
85   case $1 in
86     -h|--help) cat <<........fin
[4347]87           $0 [-nconly] [-ncvars var1,var2,...] [-pre prefix] [location_in_the_code] routine_name
88           The prefix will be put on each variable stored in the nc file to avoid duplicate
89                variables names
90           If -ncvars is not specified, all the variables are output
91           The prefix is used to prevent having twice the same name if the same variable is
92              output at two locations in the code.
93           location_in_the_code can be : -before_return               (the default valuer)
94                                         -after_declarations
95                                         -before_line  "line in code"
96                                         -after_line   "line in code"
97                                         -before_call  "param_name"   (TO BE DONE)
98                                         -after_call   "param_name"   (TO BE DONE)
[4346]99........fin
100        exit ;;
101     -nconly) nconly=true ; shift ;;
[4347]102     -before_line|-after_line|-before_call|-after_call) where="$1 $2" ; shift ; shift ;;
103     -before_return|-after_declarations) where=$1 ; shift ;;
[4346]104     -pre) prefix=$2 ; shift ; shift ;;
[4347]105     -ncvars) ncvars="`echo $2 | sed -e 's/,/ /g'`" ; shift ; shift ;;
[4346]106     *) if (( $# > 1 )) ; then $0 -h ; exit ; fi ; param=`basename $1 .F90` ; shift
107    esac
108done
109if [ "$param" = "" ] ; then $0 -h ; exit ; fi
110
[4337]111case $param in
112   thermcell_main|thermcell_plume_6A|thermcell_env|thermcell_height|thermcell_dry|\
113      thermcell_closure|thermcell_height|thermcell_dq|thermcell_flux2|thermcell_down) \
114      paramini=thermcell_ini ; inimod=thermcell_ini_mod ; klon=ngrid ; klev=nlay ;;
115   wake|wake_popdyn_2) paramini=wake_ini ; inimod=wake_ini_mod ; klon=klon ; klev=klev ;;
116   *) echo Cas non prevu ; exit
117esac
118
119replay_comment="replay automatic include"
[4346]120paraminc1=dump_replay_${param}_head.h
121paraminc2=dump_replay_${param}_nc_${prefix}.h
122iniinc=dump_replay_ini.h
123paramfile=`grep -i "subro.* ${param}[\ (]" *.F90 | sed -e 's/ //g' | grep "${param}(" | cut -d: -f1`
[4347]124echo ===================================================================================
125echo Equiping $param contained in file $paramfile
[4346]126if [ `echo ${paramfile} | wc -w` != 1 ] ; then echo file $paramfile multiple  ; $0 -h ; exit ; fi
[4337]127
[4346]128
[4337]129#-----------------------------------------------------------------------------
130# Transformer l'entete d'une subroutine en un call
131#-----------------------------------------------------------------------------
132
133function get_subroutine_arg(){
134   cat $2 | tr '[A-Z]' '[a-z]' > tmp
135   line1=`sed -n -e '/subrou.*'\`echo $1 | tr '[A-Z]' '[a-z]'\`'.*(/=' tmp | head -1 `
136   line2=`tail -n +$line1 tmp | sed -n -e '/)/=' | head -1`
137   tail -n +$line1 tmp | sed -n -e 1,${line2}p
138}
139
140#-----------------------------------------------------------------------------
141function dump_param_open(){
142#-----------------------------------------------------------------------------
143# Opening an direct access file with one record per time-step
144# Each record has the size and contains the arguments in and inout of the
145# routine
146#-----------------------------------------------------------------------------
147inout=$1 ; shift
148case $inout in
149   out) fort=81 ;;
150   in) fort=82
151esac
152echo '! <<< dump_param_open'
153for var in $* ; do echo 'rec_length=rec_length+kind('$var')*size(['$var'])' ; done
154cat <<eod
155open(${fort},file='dump_param_${inout}.bin',form='unformatted',access='direct',recl=rec_length)  ! $replay_comment
156eod
157echo '! dump_param_open >>> '
158}
159
[4346]160
[4337]161#-----------------------------------------------------------------------------
162function extract_subroutine(){
163#-----------------------------------------------------------------------------
164   # $1 nom de la subroutine
165   # $2 nom du fichier
166   # input <- routine under treatment with small caps only
[4347]167   ( cpp $2 2>/dev/null ) | tr '[A-Z]' '[a-z]' > tmp
[4337]168   name_min=`echo $1 | tr '[A-Z]' '[a-z]'`
169   line1=`sed -n -e "/subrou.*${name_min}.*(/=" tmp | head -1 `
170   tail -n +$line1 tmp > tmp2
171   line2=`sed -n -e "/[Rr][Ee][Tt][Uu][Rr][Nn]/=" tmp2 | head -1`
172   head -$line2 tmp2  > input
173   \rm -f tmp tmp2
174}
175
[4346]176
[4337]177#-----------------------------------------------------------------------------
178function include_line(){
179#-----------------------------------------------------------------------------
180   # Including param_dump*.h in the parameterization
[4347]181   #set -vx
182   line_to_be_included=$1  ; shift
183   param_=$1 ; shift
184   paramfile_=$1 ; shift
[4337]185   name_min=`echo $param_ | tr [A-Z] [a-z]`
186   line_subroutine=`cat $paramfile_ | tr '[A-Z]' '[a-z]' | sed -n -e "/subrou.*${name_min}.*(/=" | head -1 `
[4347]187   tail -n +$line_subroutine $paramfile_ > tmp # file starting at the subroutine instruction
[4337]188   line_return=`sed -n -e "/[Rr][Ee][Tt][Uu][Rr][Nn]/=" tmp | head -1`
[4347]189   head -$line_return tmp > tmp2               # file containing the routine
190   sed -e 's/\!.*$//' tmp2 > tmp3
191   cpp tmp2 > tmp3 2>/dev/null
192   cat tmp3 | tr '[A-Z]' '[a-z]' > tmp2_cpp   # same after cpp filtering
193   last_line_declaration2="`sed -n -e 's/\!.*$//' -e 's/^/ /' -e '/[\ ,]real[\ ,]/p' -e '/[\ ,]integer[\ ,]/p' -e '/[\ ,]logical[\ ,]/p' -e '/[\ ,]character[\ ,]/p' tmp2_cpp | tail -1 | sed -e 's/  / /g' -e 's/ /.*/g'`"
194   line_last_declaration=`cat tmp2 | tr '[A-Z]' '[a-z]' | sed -n -e "/$last_line_declaration2/="`
195   if [ "$line_last_declaration" = "" ] ; then echo line_last_declaration $line_last_declaration line $last_line_declaration2  ; exit ; fi
196   if (( $# > 0 )) ; then
197      wtype=`echo $1 | awk ' { print $1 } '`
198      case $wtype in
199         -after_declarations)      targeted_line=$line_last_declaration ;;
200         -before_return)           targeted_line=$line_return ;;
201         -before_line|-after_line) linestr=`echo $1 | sed -e "s/$wtype //"` ; targeted_line=`sed -n -e "/$linestr/=" tmp2` ;;
202         *)                  echo Cas non prevu 0 where=$where in inclide_file
203      esac
204      case $wtype in
205         -after_declarations|-after_line)  line0=$(( $line_subroutine - 1 )) ;;
206         -before_return|-before_line)      line0=$(( $line_subroutine - 2 )) ;;
207         *)                  echo Cas non prevu 1 where=$where in inclide_file
208      esac
209      echo Including line $line0 in $paramfile_ the line : $line_to_be_included
210      linebefore_include=$(( $line0 + $targeted_line ))
211     sed -i'' -e $linebefore_include"s/$/\n $line_to_be_included \!  $replay_comment/" $paramfile_ 
212   fi
[4337]213}
214
215
[4346]216
217
[4337]218#-----------------------------------------------------------------------------
219function block_Replay0() {
220#-----------------------------------------------------------------------------
221condition=$1 ; shift
222suf1=$1 ; shift
223suf2=$1 ; shift
224if [ $# -gt 0 ] ; then
225   vars=$*
226   echo '   if ('$condition') then'
227   for var in $vars ; do echo '      '$var$suf1=$var$suf2 ; done
228   echo '   endif'
229fi
230}
231
232#-----------------------------------------------------------------------------
[4346]233function iotd_calls(){
[4337]234#-----------------------------------------------------------------------------
[4347]235    klev_=$1 ; shift
[4346]236    pre=$1 ; shift
237    if (( $# >> 0 )) ; then
238       vars=$*
239       for var in $vars ; do
[4347]240          echo "call iotd_ecrit_seq('"$pre$var"',$klev_,'"$pre$var in $param"',' ',"$var")"
[4346]241       done
242    fi
243}
244         
[4347]245#-----------------------------------------------------------------------------
246function b_among_a() {
247#-----------------------------------------------------------------------------
248   a="$1"
249   b="$2"
250   o=""
251   for v in $a ; do
252       for vv in $b ; do
253           if [ "$v" = "$vv" ] ; then o="$o $v" ;  fi
254       done
255   done
256   echo $o
257}
[4337]258
[4347]259
[4337]260#-----------------------------------------------------------------------------
[4346]261# On nettoye les inclusions précédente dans les fichiers .F90
[4337]262#-----------------------------------------------------------------------------
263
[4346]264if [ $nconly = false ] ; then
265   for file in `grep "$replay_comment" *.F90 2> /dev/null | cut -d: -f1` ; do
266      sed -i"" -e "/$replay_comment/d" $file
267   done
268   line=`sed -n -e "/CALL wake_ini/=" physiq_mod.F90 | head -1`
269   sed -i"" -e "${line}s/$/\n   CALL iophys_ini(pdtphys) ! $replay_comment  ! $replay_comment/" physiq_mod.F90
270fi
[4337]271
272#-----------------------------------------------------------------------------
[4347]273# Analysis of the variables to be stored and there nature
[4337]274#-----------------------------------------------------------------------------
275
[4346]276extract_subroutine $param $paramfile # -> input file
[4337]277varin0=`grep inten.*.in input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
[4353]278varinout0=`grep inten.*.inout input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
[4337]279varin=`echo $varin0 | sed -e 's/ /,/g' -e "s/,,,/,/g" -e "s/,,/,/g"`
280output=full # Attention, l'option full ne marche pas a cause de tableaux locaux undef
281nvar0D=0 ; nvar1D=0 ; nvar2D=0
282case $output in
283   light) search_str='real.*intent' ;;
284   full) search_str='real'
285esac
[4346]286var_1D_inout=`grep -i "$search_str" input | grep intent.*inout | grep $klon | sed -e 's/!.*$//' -e /$klev/d | cut -d: -f3 | sed -e 's/,/ /g'`
287var_2D_inout=`grep -i "$search_str" input | grep intent.*inout | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
[4337]288var_1D_noarg=`grep -i "$search_str" input | sed -e /intent/d | grep $klon | sed -e 's/!.*$//' -e /$klev/d | cut -d: -f3 | sed -e 's/,/ /g'`
289var_2D_noarg=`grep -i "$search_str" input | sed -e /intent/d | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
290var_1D=`grep -i "$search_str" input | grep $klon | sed -e 's/!.*$//' -e /$klev/d | cut -d: -f3 | sed -e 's/,/ /g'`
291var_2D=`grep -i "$search_str" input | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
[4347]292if [ "$ncvars" != "" ] ; then
293   var_1D=`b_among_a "$var_1D" "$ncvars"`
294   var_2D=`b_among_a "$var_2D" "$ncvars"`
295fi
296echo Variables in and inout : $varin0
297echo 1D variables "(all)" : $var_1D
298echo 2D variables "(all)" : $var_2D
299echo 1D variables "intent(inout)" : $var_1D_inout
300echo 2D variables "intent(inout)" : $var_2D_inout
301echo local 1D variables : $var_1D_noarg
302echo local 2D variables : $var_2D_noarg
[4337]303
304#-----------------------------------------------------------------------------
305# Ecriture de la routine d'appel a la parametrisation en mode replay
306#-----------------------------------------------------------------------------
307
[4346]308if [ $nconly = false ] ; then
309
[4337]310cat > call_param_replay.F90 <<eod
311subroutine call_param_replay($klon,$klev)
312USE IOIPSL, ONLY : getin
313IMPLICIT NONE
314integer :: ifin,irec,it,rec_length=0,replay_irec0=1,replay_nt=1000
315eod
316grep 'intent.*::' input | sed -e 's/ //g' -e 's/,intent(.*[nt])//'>> call_param_replay.F90
317# duplicating declaration for inout variables
[4353]318
[4337]319for var in $varinout0 ; do
320    sed -e 's/::/ :: /' -e 's/,/ , /g' -e 's/$/ /' input | grep 'intent.*inout.*::.* '$var' ' | sed -e 's/ //g' -e 's/,intent(.*[nt])//' | sed -e 's/::.*$/, allocatable, save :: '$var'_Replay0/' | sed -e 's/'$klon'/:/' -e 's/'$klev'/:/' >> call_param_replay.F90
321done
322# Initalisation, shared with dump_param1.sh
323dump_param_open "in" $varin0 >> call_param_replay.F90
324for var in $varinout0 ; do
325    sed -e 's/::/ :: /' -e 's/,/ , /g' -e 's/$/ /' input | grep 'intent.*inout.*::.* '$var' ' | sed -e 's/intent(.*t)//' -e 's/^.*(/allocate('$var'_Replay0(/' -e 's/).*$/))/' >> call_param_replay.F90
326done
327
328cat >> call_param_replay.F90 <<eod
329call getin('replay_nt',replay_nt)
330call getin('replay_irec0',replay_irec0)
331do it=1,replay_nt
332   if (replay_irec0>=0) then
333       irec=replay_irec0+it-1
334   else
335       irec=-replay_irec0
336   endif
337   print*,'Time step',it,', reading record',irec,'in dump_param.bin'
338   read(82,rec=irec,iostat=ifin) $varin
339   if (.NOT. ifin == 0 ) stop "Fin du fichier fort.82"
340eod
341
342block_Replay0 "it == 1"          _Replay0   ""       $varinout0 >> call_param_replay.F90
343block_Replay0 "replay_irec0 < 0" ""         _Replay0 $varinout0 >> call_param_replay.F90
344get_subroutine_arg $param $paramfile | sed -e 's/subroutine/   call/' >> call_param_replay.F90
345block_Replay0 "replay_irec0 < 0" _Replay0   ""       $varinout0 >> call_param_replay.F90
346cat >> call_param_replay.F90 <<eod
347enddo
348return
349end
350eod
351
[4346]352fi # nconly = false
[4337]353
354#-----------------------------------------------------------------------------
[4346]355# Creating file dump_${param}_head.h
[4337]356#-----------------------------------------------------------------------------
357
[4347]358if [ $nconly = false ] ; then
[4337]359\rm $paraminc1
360cat> $paraminc1 <<eod
361logical, save :: first=.true.
362integer, save :: rec_length=0,irec=0
363if (first) then
364eod
365dump_param_open out $varin0 >> $paraminc1
366cat>> $paraminc1 <<eod
367first=.false.
368endif
369irec=irec+1
370write(81,rec=irec) $varin
371eod
[4346]372iotd_calls 1     in_${prefix} $var_1D_inout >> $paraminc1
373iotd_calls $klev in_${prefix} $var_2D_inout >> $paraminc1
374fi # nconly = false
375
[4347]376if [ "`grep $paraminc1 $paramfile`" = "" ] ; then
377   # Not changing $paraminc1 if it is already included in the file
378   # To allow adding new nc outputs in a routine equiped for replay
379   for var in $var_1D_noarg $var_2D_noarg ; do echo $var=0. >> $paraminc1 ; done
380   include_line "include \"$paraminc1\"" $param $paramfile -after_declarations
381fi
[4337]382
[4346]383#-----------------------------------------------------------------------------
384# Creating file dump_${param}_nc_${prefix}.h
385#-----------------------------------------------------------------------------
386
[4337]387\rm $paraminc2
[4346]388iotd_calls 1     "${prefix}" $var_1D >> $paraminc2
389iotd_calls $klev "${prefix}" $var_2D >> $paraminc2
[4347]390include_line "include \"$paraminc2\"" $param $paramfile "$where"
[4337]391 
392#-----------------------------------------------------------------------------
393# dump_ini_module gere l'ecriture des variables d'interface de l'intialisation
394# du module en mode replay
395#-----------------------------------------------------------------------------
396
[4346]397if [ $nconly = false ] ; then
[4337]398varinmod=`grep -i 'intent.in' $inimod.F90 | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
399varinmodv=`echo $varinmod | sed -e 's/ /,/g'`
400cat > $iniinc <<eod
401open(90,file='$inimod.bin',form='unformatted')
402write(90) $varinmodv
403close(90)
404eod
[4347]405include_line "include \"$iniinc\"" $paramini $inimod.F90  -before_return
[4346]406fi # nconly = false
[4337]407
408
409#-----------------------------------------------------------------------------
410# get_ini_module gere l'initialisation du module en mode replay
411#-----------------------------------------------------------------------------
[4346]412if [ $nconly = false ] ; then
[4337]413cat > get_ini_module.F90 <<eod
414subroutine get_ini_module
415use $inimod
416IMPLICIT NONE
417eod
418grep -i intent.in $inimod.F90  |  tr '[A-Z]' '[a-z]' | sed -e 's/,.*intent.i.*)//' >> get_ini_module.F90
419cat >> get_ini_module.F90 <<eod
420open(90,file='$inimod.bin',form='unformatted')
421read(90) $varinmodv
422close(90)
423eod
424#get_subroutine_arg $paramini $inimod.F90 ; exit
425get_subroutine_arg $paramini $inimod.F90 | sed -e 's/subroutine/call/' >> get_ini_module.F90
426cat >> get_ini_module.F90 <<eod
427return
428end
429eod
[4346]430fi # nconly = false
[4337]431
432#-----------------------------------------------------------------------------
433# Inclusion de l'ecriture de l'interface de l'initialisation
434#-----------------------------------------------------------------------------
435
436
437#\rm -f tmp input
Note: See TracBrowser for help on using the repository browser.