source: BOL/Replay/replay_equip.sh @ 5008

Last change on this file since 5008 was 4681, checked in by fhourdin, 15 months ago

Details

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