source: BOL/Replay/replay_equip.sh @ 4367

Last change on this file since 4367 was 4360, checked in by fhourdin, 20 months ago

replay tool details

File size: 18.1 KB
Line 
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
76#-----------------------------------------------------------------------------
77# Reading rguments
78#-----------------------------------------------------------------------------
79nconly=false
80where=-before_return
81
82if [ $# = 0 ] ; then $0 -h ; exit ; fi
83while (($# > 0))
84   do
85   case $1 in
86     -h|--help) cat <<........fin
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)
99........fin
100        exit ;;
101     -nconly) nconly=true ; shift ;;
102     -before_line|-after_line|-before_call|-after_call) where="$1 $2" ; shift ; shift ;;
103     -before_return|-after_declarations) where=$1 ; shift ;;
104     -pre) prefix=$2 ; shift ; shift ;;
105     -ncvars) ncvars="`echo $2 | sed -e 's/,/ /g'`" ; shift ; shift ;;
106     *) if (( $# > 1 )) ; then $0 -h ; exit ; fi ; param=`basename $1 .F90` ; shift
107    esac
108done
109if [ "$param" = "" ] ; then $0 -h ; exit ; fi
110
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"
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`
124echo ===================================================================================
125echo Equiping $param contained in file $paramfile
126if [ `echo ${paramfile} | wc -w` != 1 ] ; then echo file $paramfile multiple  ; $0 -h ; exit ; fi
127
128
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_replay=rec_length_replay+kind('$var')*size(['$var'])' ; done
154cat <<eod
155open(${fort},file='dump_param_${inout}.bin',form='unformatted',access='direct',recl=rec_length_replay)  ! $replay_comment
156eod
157echo '! dump_param_open >>> '
158}
159
160
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
167   ( cpp $2 2>/dev/null ) | tr '[A-Z]' '[a-z]' > tmp
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
176
177#-----------------------------------------------------------------------------
178function include_line(){
179#-----------------------------------------------------------------------------
180   # Including param_dump*.h in the parameterization
181   #set -vx
182   line_to_be_included=$1  ; shift
183   param_=$1 ; shift
184   paramfile_=$1 ; shift
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 `
187   tail -n +$line_subroutine $paramfile_ > tmp # file starting at the subroutine instruction
188   line_return=`sed -n -e "/[Rr][Ee][Tt][Uu][Rr][Nn]/=" tmp | head -1`
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
213}
214
215
216
217
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#-----------------------------------------------------------------------------
233function iotd_calls(){
234#-----------------------------------------------------------------------------
235    klev_=$1 ; shift
236    pre=$1 ; shift
237    if (( $# >> 0 )) ; then
238       vars=$*
239       for var in $vars ; do
240          echo "call iotd_ecrit_seq('"$pre$var"',$klev_,'"$pre$var in $param"',' ',"$var")"
241       done
242    fi
243}
244         
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}
258
259
260#-----------------------------------------------------------------------------
261# On nettoye les inclusions précédente dans les fichiers .F90
262#-----------------------------------------------------------------------------
263
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
271
272#-----------------------------------------------------------------------------
273# Analysis of the variables to be stored and there nature
274#-----------------------------------------------------------------------------
275
276extract_subroutine $param $paramfile # -> input file
277varin0=`grep inten.*.in input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
278varinout0=`grep inten.*.inout input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
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
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'`
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'`
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
303
304#-----------------------------------------------------------------------------
305# Ecriture de la routine d'appel a la parametrisation en mode replay
306#-----------------------------------------------------------------------------
307
308if [ $nconly = false ] ; then
309
310cat > call_param_replay.F90 <<eod
311subroutine call_param_replay($klon,$klev)
312USE IOIPSL, ONLY : getin
313IMPLICIT NONE
314integer :: ifin,irec,it,rec_length_replay=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
318
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
352fi # nconly = false
353
354#-----------------------------------------------------------------------------
355# Creating file dump_${param}_head.h
356#-----------------------------------------------------------------------------
357
358if [ $nconly = false ] ; then
359\rm $paraminc1
360cat> $paraminc1 <<eod
361logical, save :: first_replay=.true.
362integer, save :: rec_length_replay=0,irec=0
363if (first_replay) then
364eod
365dump_param_open out $varin0 >> $paraminc1
366cat>> $paraminc1 <<eod
367first_replay=.false.
368endif
369irec=irec+1
370write(81,rec=irec) $varin
371eod
372iotd_calls 1     in_${prefix} $var_1D_inout >> $paraminc1
373iotd_calls $klev in_${prefix} $var_2D_inout >> $paraminc1
374fi # nconly = false
375
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
382
383#-----------------------------------------------------------------------------
384# Creating file dump_${param}_nc_${prefix}.h
385#-----------------------------------------------------------------------------
386
387\rm $paraminc2
388iotd_calls 1     "${prefix}" $var_1D >> $paraminc2
389iotd_calls $klev "${prefix}" $var_2D >> $paraminc2
390include_line "include \"$paraminc2\"" $param $paramfile "$where"
391 
392#-----------------------------------------------------------------------------
393# dump_ini_module gere l'ecriture des variables d'interface de l'intialisation
394# du module en mode replay
395#-----------------------------------------------------------------------------
396
397if [ $nconly = false ] ; then
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
405include_line "include \"$iniinc\"" $paramini $inimod.F90  -before_return
406fi # nconly = false
407
408
409#-----------------------------------------------------------------------------
410# get_ini_module gere l'initialisation du module en mode replay
411#-----------------------------------------------------------------------------
412if [ $nconly = false ] ; then
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
430fi # nconly = false
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.