source: BOL/Replay/replay_equip.sh @ 4639

Last change on this file since 4639 was 4614, checked in by fhourdin, 15 months ago

Inclusion de lmdz_ratqs*

File size: 19.8 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 : sous programme d'appelle en boucle à la param
55#  * dump_ini_module.F90   : écriture de l'interface "in" de param_ini
56#  * call_ini_replay.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   vdif_k) paramini=None ; inimod=None ; klon=ngrid ; klev=nlay ;;
113   thermcell_main|thermcell_plume_6A|thermcell_env|thermcell_height|thermcell_dry|\
114      thermcell_closure|thermcell_height|thermcell_dq|thermcell_flux2|thermcell_down| \
115      thermcell_updown_dq) \
116      paramini=thermcell_ini ; inimod=lmdz_thermcell_ini ; klon=ngrid ; klev=nlay ;;
117   wake|wake_popdyn_1|wake_popdyn_2) paramini=wake_ini ; inimod=lmdz_wake_ini ; klon=klon ; klev=klev ;;
118   ratqs_main|ratqs_inter|ratqs_oro|ratqs_hetero|ratqs_tke) paramini=ratqs_ini ; inimod=lmdz_ratqs_ini ; klon=klon ; klev=klev ;;
119   *) echo Cas non prevu ; exit
120esac
121
122replay_comment="replay automatic include"
123paraminc1=dump_replay_${param}_head.h
124paraminc2=dump_replay_${param}_nc_${prefix}.h
125iniinc=dump_replay_ini.h
126paramfile=`grep -i "subro.* ${param}[\ (]" *.F90 | sed -e 's/ //g' | grep "${param}(" | cut -d: -f1`
127echo ===================================================================================
128echo Equiping $param contained in file $paramfile
129if [ `echo ${paramfile} | wc -w` != 1 ] ; then echo file $paramfile multiple  ; $0 -h ; exit ; fi
130
131
132#-----------------------------------------------------------------------------
133# Transformer l'entete d'une subroutine en un call
134#-----------------------------------------------------------------------------
135
136function get_subroutine_arg(){
137   cat $2 | tr '[A-Z]' '[a-z]' > tmp
138   line1=`sed -n -e '/subrou.*'\`echo $1 | tr '[A-Z]' '[a-z]'\`'.*(/=' tmp | head -1 `
139   line2=`tail -n +$line1 tmp | sed -n -e '/)/=' | head -1`
140   tail -n +$line1 tmp | sed -n -e 1,${line2}p
141}
142
143#-----------------------------------------------------------------------------
144function dump_param_open(){
145    #-----------------------------------------------------------------------------
146    # Opening an direct access file with one record per time-step
147    # Each record has the size and contains the arguments in and inout of the
148    # routine
149    #-----------------------------------------------------------------------------
150    inout=$1 ; shift
151    case $inout in
152       out) fort=81 ;;
153       in) fort=82
154    esac
155    echo '! <<< dump_param_open'
156    for var in $* ; do echo 'rec_length_replay=rec_length_replay+kind('$var')*size(['$var'])' ; done
157    cat <<....eod
158    open(${fort},file='dump_param_${inout}.bin',form='unformatted',access='direct',recl=rec_length_replay)  ! $replay_comment
159....eod
160    echo '! dump_param_open >>> '
161}
162
163
164#-----------------------------------------------------------------------------
165function extract_subroutine(){
166#-----------------------------------------------------------------------------
167   # $1 nom de la subroutine
168   # $2 nom du fichier
169   # input <- routine under treatment with small caps only
170   ( cpp $2 2>/dev/null ) | tr '[A-Z]' '[a-z]' > tmp
171   name_min=`echo $1 | tr '[A-Z]' '[a-z]'`
172   line1=`sed -n -e "/subrou.*${name_min}.*(/=" tmp | head -1 `
173   tail -n +$line1 tmp > tmp2
174   line2=`sed -n -e "/[Rr][Ee][Tt][Uu][Rr][Nn]/=" tmp2 | head -1`
175   head -$line2 tmp2  > input
176   \rm -f tmp tmp2
177}
178
179
180#-----------------------------------------------------------------------------
181function echo_use_module(){
182#-----------------------------------------------------------------------------
183# Regle tacite : l'instruction MODULE commence à la premiere colonne.
184#                Existe-t-i une facon de la faire tomber ?
185#                En enlevant tous les blanc dans le input sans doute ...
186   param_=$1 ; shift
187   paramfile_=$1
188   if [ ! -f $paramfile_ ] ; then echo plantage which_module ; exit 1 ; fi
189   module=`grep '^[mM][oO][dD][uU][lL][eE] .*[a-Z]' $paramfile_ | head -1 | awk ' { print $2 } '`
190   if [ "$module" != "" ] ; then
191       echo USE $module, ONLY : $param_
192   fi
193}
194
195#-----------------------------------------------------------------------------
196function include_line(){
197#-----------------------------------------------------------------------------
198   # Including param_dump*.h in the parameterization
199   #set -vx
200   line_to_be_included=$1  ; shift
201   param_=$1 ; shift
202   paramfile_=$1 ; shift
203   name_min=`echo $param_ | tr [A-Z] [a-z]`
204   line_subroutine=`cat $paramfile_ | tr '[A-Z]' '[a-z]' | sed -n -e "/subrou.*${name_min}.*(/=" | head -1 `
205   tail -n +$line_subroutine $paramfile_ > tmp # file starting at the subroutine instruction
206   line_return=`sed -n -e "/[Rr][Ee][Tt][Uu][Rr][Nn]/=" tmp | head -1`
207   head -$line_return tmp > tmp2               # file containing the routine
208   sed -e 's/\!.*$//' tmp2 > tmp3
209   cpp tmp2 > tmp3 2>/dev/null
210   cat tmp3 | tr '[A-Z]' '[a-z]' > tmp2_cpp   # same after cpp filtering
211   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'`"
212   line_last_declaration=`cat tmp2 | tr '[A-Z]' '[a-z]' | sed -n -e "/$last_line_declaration2/="`
213   echo OK0
214   if [ "`grep -i 'end.*module' $paramfile_`" = "" ] ; then echo aka ;  line_end_module=`wc -l $paramfile_ | awk ' { print $1 } '` ; else echo akb ; line_end_module=`sed -n -e '/[eE][nN][dD] .*[mM][oO][dD][uU][lL][eE]/=' $paramfile_` ; fi
215   echo OK1
216   echo $line_end_module
217   if [ "$line_last_declaration" = "" ] ; then echo line_last_declaration $line_last_declaration line $last_line_declaration2  ; exit ; fi
218   if (( $# > 0 )) ; then
219      wtype=`echo $1 | awk ' { print $1 } '`
220      case $wtype in
221         -after_declarations)      targeted_line=$line_last_declaration ;;
222         -before_return)           targeted_line=$line_return ;;
223         -before_end_module)       targeted_line=$line_end_module ;;
224         -before_line|-after_line) linestr=`echo $1 | sed -e "s/$wtype //"` ; targeted_line=`sed -n -e "/$linestr/=" tmp2` ;;
225         *)                  echo Cas non prevu 0 where=$where in include_file
226      esac
227      case $wtype in
228         -after_declarations|-after_line)  line0=$(( $line_subroutine - 1 )) ;;
229         -before_return|-before_line)      line0=$(( $line_subroutine - 2 )) ;;
230         -before_end_module)               line0=-1 ;;
231         *)                  echo Cas non prevu 1 where=$where in include_file
232      esac
233      echo Including line $line0 + $targeted_line in $paramfile_ the line : $line_to_be_included
234      linebefore_include=$(( $line0 + $targeted_line ))
235     sed -i'' -e $linebefore_include"s/$/\n $line_to_be_included \!  $replay_comment/" $paramfile_ 
236   fi
237}
238
239
240
241
242#-----------------------------------------------------------------------------
243function block_Replay0() {
244#-----------------------------------------------------------------------------
245condition=$1 ; shift
246suf1=$1 ; shift
247suf2=$1 ; shift
248if [ $# -gt 0 ] ; then
249   vars=$*
250   echo '   if ('$condition') then'
251   for var in $vars ; do echo '      '$var$suf1=$var$suf2 ; done
252   echo '   endif'
253fi
254}
255
256#-----------------------------------------------------------------------------
257function iotd_calls(){
258#-----------------------------------------------------------------------------
259    klev_=$1 ; shift
260    pre=$1 ; shift
261    if (( $# >> 0 )) ; then
262       vars=$*
263       for var in $vars ; do
264          echo "call iotd_ecrit_seq('"$pre$var"',$klev_,'"$pre$var in $param"',' ',"$var")"
265       done
266    fi
267}
268         
269#-----------------------------------------------------------------------------
270function b_among_a() {
271#-----------------------------------------------------------------------------
272   a="$1"
273   b="$2"
274   o=""
275   for v in $a ; do
276       for vv in $b ; do
277           if [ "$v" = "$vv" ] ; then o="$o $v" ;  fi
278       done
279   done
280   echo $o
281}
282
283
284#-----------------------------------------------------------------------------
285# On nettoye les inclusions précédente dans les fichiers .F90
286#-----------------------------------------------------------------------------
287
288if [ $nconly = false ] ; then
289   for file in `grep "$replay_comment" *.F90 2> /dev/null | cut -d: -f1` ; do
290      sed -i"" -e "/$replay_comment/d" $file
291   done
292   line=`sed -n -e "/CALL wake_ini/=" physiq_mod.F90 | head -1`
293   sed -i"" -e "${line}s/$/\n   CALL iophys_ini(pdtphys) ! $replay_comment  ! $replay_comment/" physiq_mod.F90
294fi
295
296#-----------------------------------------------------------------------------
297# Analysis of the variables to be stored and there nature
298#-----------------------------------------------------------------------------
299
300extract_subroutine $param $paramfile # -> input file
301varin0=`grep inten.*.in input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
302varinout0=`grep inten.*.inout input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
303varin=`echo $varin0 | sed -e 's/ /,/g' -e "s/,,,/,/g" -e "s/,,/,/g"`
304output=full # Attention, l'option full ne marche pas a cause de tableaux locaux undef
305nvar0D=0 ; nvar1D=0 ; nvar2D=0
306case $output in
307   light) search_str='real.*intent' ;;
308   full) search_str='real'
309esac
310var_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'`
311var_2D_inout=`grep -i "$search_str" input | grep intent.*inout | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
312var_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'`
313var_2D_noarg=`grep -i "$search_str" input | sed -e /intent/d | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
314var_1D=`grep -i "$search_str" input | grep $klon | sed -e 's/!.*$//' -e /$klev/d | cut -d: -f3 | sed -e 's/,/ /g'`
315var_2D=`grep -i "$search_str" input | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
316if [ "$ncvars" != "" ] ; then
317   var_1D=`b_among_a "$var_1D" "$ncvars"`
318   var_2D=`b_among_a "$var_2D" "$ncvars"`
319fi
320echo Variables in and inout : $varin0
321echo 1D variables "(all)" : $var_1D
322echo 2D variables "(all)" : $var_2D
323echo 1D variables "intent(inout)" : $var_1D_inout
324echo 2D variables "intent(inout)" : $var_2D_inout
325echo local 1D variables : $var_1D_noarg
326echo local 2D variables : $var_2D_noarg
327
328#-----------------------------------------------------------------------------
329# Ecriture de la routine d'appel a la parametrisation en mode replay
330#-----------------------------------------------------------------------------
331
332if [ $nconly = false ] ; then
333
334cat > call_param_replay.F90 <<eod
335subroutine call_param_replay($klon,$klev)
336USE IOIPSL, ONLY : getin
337`echo_use_module $param  $paramfile`
338IMPLICIT NONE
339integer :: ifin,irec,it,rec_length_replay=0,replay_irec0=1,replay_nt=1000
340eod
341grep 'intent.*::' input | sed -e 's/ //g' -e 's/,intent(.*[nt])//'>> call_param_replay.F90
342# duplicating declaration for inout variables
343
344for var in $varinout0 ; do
345    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
346done
347# Initalisation, shared with dump_param1.sh
348dump_param_open "in" $varin0 >> call_param_replay.F90
349for var in $varinout0 ; do
350    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
351done
352
353cat >> call_param_replay.F90 <<eod
354call getin('replay_nt',replay_nt)
355call getin('replay_irec0',replay_irec0)
356do it=1,replay_nt
357   if (replay_irec0>=0) then
358       irec=replay_irec0+it-1
359   else
360       irec=-replay_irec0
361   endif
362   print*,'Time step',it,', reading record',irec,'in dump_param.bin'
363   read(82,rec=irec,iostat=ifin) $varin
364   if (.NOT. ifin == 0 ) stop "Fin du fichier fort.82"
365eod
366
367block_Replay0 "it == 1"          _Replay0   ""       $varinout0 >> call_param_replay.F90
368block_Replay0 "replay_irec0 < 0" ""         _Replay0 $varinout0 >> call_param_replay.F90
369get_subroutine_arg $param $paramfile | sed -e 's/subroutine/   call/' >> call_param_replay.F90
370block_Replay0 "replay_irec0 < 0" _Replay0   ""       $varinout0 >> call_param_replay.F90
371cat >> call_param_replay.F90 <<eod
372enddo
373return
374end
375eod
376
377fi # nconly = false
378
379#-----------------------------------------------------------------------------
380# Creating file dump_${param}_head.h
381#-----------------------------------------------------------------------------
382
383if [ $nconly = false ] ; then
384\rm $paraminc1
385cat> $paraminc1 <<eod
386logical, save :: first_replay=.true.
387integer, save :: rec_length_replay=0,irec=0
388if (first_replay) then
389eod
390dump_param_open out $varin0 >> $paraminc1
391cat>> $paraminc1 <<eod
392first_replay=.false.
393endif
394irec=irec+1
395write(81,rec=irec) $varin
396eod
397iotd_calls 1     in_${prefix} $var_1D_inout >> $paraminc1
398iotd_calls $klev in_${prefix} $var_2D_inout >> $paraminc1
399fi # nconly = false
400
401if [ "`grep $paraminc1 $paramfile`" = "" ] ; then
402   # Not changing $paraminc1 if it is already included in the file
403   # To allow adding new nc outputs in a routine equiped for replay
404   for var in $var_1D_noarg $var_2D_noarg ; do echo $var=0. >> $paraminc1 ; done
405   include_line "include \"$paraminc1\"" $param $paramfile -after_declarations
406fi
407
408#-----------------------------------------------------------------------------
409# Creating file dump_${param}_nc_${prefix}.h
410#-----------------------------------------------------------------------------
411
412\rm $paraminc2
413iotd_calls 1     "${prefix}" $var_1D >> $paraminc2
414iotd_calls $klev "${prefix}" $var_2D >> $paraminc2
415include_line "include \"$paraminc2\"" $param $paramfile "$where"
416 
417#-----------------------------------------------------------------------------
418# dump_ini_module gere l'ecriture des variables d'interface de l'intialisation
419# du module en mode replay
420#-----------------------------------------------------------------------------
421
422if [ $nconly = false -a $paramini != None ] ; then
423   varinmod=`grep -i 'intent.in' $inimod.F90 | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
424   varinmodv=`echo $varinmod | sed -e 's/ /,/g'`
425   cat > $iniinc <<...eod...............................................
426   open(90,file='$inimod.bin',form='unformatted')
427   write(90) $varinmodv
428   close(90)
429...eod...............................................
430   include_line "include \"$iniinc\"" $paramini $inimod.F90  -before_return
431fi # nconly = false
432
433
434#-----------------------------------------------------------------------------
435# call_ini_replay.F90 gere l'initialisation du module en mode replay
436#-----------------------------------------------------------------------------
437if [ $nconly = false -a $paramini != None ] ; then
438    cat > call_ini_replay.F90 <<....eod............................................
439    subroutine call_ini_replay
440    use $inimod
441    IMPLICIT NONE
442....eod............................................
443    grep -i intent.in $inimod.F90  |  tr '[A-Z]' '[a-z]' | sed -e 's/,.*intent.i.*)//' >> call_ini_replay.F90
444    cat >> call_ini_replay.F90 <<....eod...........................................
445    open(90,file='$inimod.bin',form='unformatted')
446    read(90) $varinmodv
447    close(90)
448....eod...........................................
449    #get_subroutine_arg $paramini $inimod.F90 ; exit
450    get_subroutine_arg $paramini $inimod.F90 | sed -e 's/subroutine/call/' >> call_ini_replay.F90
451    cat >> call_ini_replay.F90 <<....eod...........................................
452    return
453    end
454....eod...........................................
455fi # nconly = false
Note: See TracBrowser for help on using the repository browser.