source: BOL/Replay/replay_equip.sh @ 4669

Last change on this file since 4669 was 4668, checked in by fhourdin, 13 months ago

Mise a jour pour lscp et fisrtilp

File size: 20.2 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) param_ini=vdif_ini_ ; inimod=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   sed -i"" -e "${line}s/^/   CALL iophys_ini(pdtphys) ! $replay_comment  ! $replay_comment\n/" physiq_mod.F90
298fi
299
300#-----------------------------------------------------------------------------
301# Analysis of the variables to be stored and there nature
302#-----------------------------------------------------------------------------
303
304extract_subroutine $param $paramfile # -> input file
305varin0=`grep inten.*.in input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
306varinout0=`grep inten.*.inout input | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
307varin=`echo $varin0 | sed -e 's/ /,/g' -e "s/,,,/,/g" -e "s/,,/,/g"`
308output=full # Attention, l'option full ne marche pas a cause de tableaux locaux undef
309nvar0D=0 ; nvar1D=0 ; nvar2D=0
310case $output in
311   light) search_str='real.*intent' ;;
312   full) search_str='real'
313esac
314var_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'`
315var_2D_inout=`grep -i "$search_str" input | grep intent.*inout | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
316var_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'`
317var_2D_noarg=`grep -i "$search_str" input | sed -e /intent/d | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
318var_1D=`grep -i "$search_str" input | grep $klon | sed -e 's/!.*$//' -e /$klev/d | cut -d: -f3 | sed -e 's/,/ /g'`
319var_2D=`grep -i "$search_str" input | grep $klon | grep $klev | cut -d: -f3 | sed -e 's/!.*$//' -e 's/,/ /g'`
320if [ "$ncvars" != "" ] ; then
321   var_1D=`b_among_a "$var_1D" "$ncvars"`
322   var_2D=`b_among_a "$var_2D" "$ncvars"`
323fi
324echo Variables in and inout : $varin0
325echo 1D variables "(all)" : $var_1D
326echo 2D variables "(all)" : $var_2D
327echo 1D variables "intent(inout)" : $var_1D_inout
328echo 2D variables "intent(inout)" : $var_2D_inout
329echo local 1D variables : $var_1D_noarg
330echo local 2D variables : $var_2D_noarg
331
332#-----------------------------------------------------------------------------
333# Ecriture de la routine d'appel a la parametrisation en mode replay
334#-----------------------------------------------------------------------------
335
336if [ $nconly = false ] ; then
337
338cat > call_param_replay.F90 <<eod
339subroutine call_param_replay($klon,$klev)
340USE IOIPSL, ONLY : getin
341`echo_use_module $param  $paramfile`
342IMPLICIT NONE
343integer :: ifin,irec,it,rec_length_replay=0,replay_irec0=1,replay_nt=1000
344eod
345grep 'intent.*::' input | sed -e 's/ //g' -e 's/,intent(.*[nt])//'>> call_param_replay.F90
346# duplicating declaration for inout variables
347
348for var in $varinout0 ; do
349    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
350done
351# Initalisation, shared with dump_param1.sh
352dump_param_open "in" $varin0 >> call_param_replay.F90
353for var in $varinout0 ; do
354    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
355done
356
357cat >> call_param_replay.F90 <<eod
358call getin('replay_nt',replay_nt)
359call getin('replay_irec0',replay_irec0)
360do it=1,replay_nt
361   if (replay_irec0>=0) then
362       irec=replay_irec0+it-1
363   else
364       irec=-replay_irec0
365   endif
366   print*,'Time step',it,', reading record',irec,'in dump_param.bin'
367   read(82,rec=irec,iostat=ifin) $varin
368   if (.NOT. ifin == 0 ) stop "Fin du fichier fort.82"
369eod
370
371block_Replay0 "it == 1"          _Replay0   ""       $varinout0 >> call_param_replay.F90
372block_Replay0 "replay_irec0 < 0" ""         _Replay0 $varinout0 >> call_param_replay.F90
373get_subroutine_arg $param $paramfile | sed -e 's/subroutine/   call/' >> call_param_replay.F90
374block_Replay0 "replay_irec0 < 0" _Replay0   ""       $varinout0 >> call_param_replay.F90
375cat >> call_param_replay.F90 <<eod
376enddo
377return
378end
379eod
380
381fi # nconly = false
382
383#-----------------------------------------------------------------------------
384# Creating file dump_${param}_head.h
385#-----------------------------------------------------------------------------
386
387if [ $nconly = false ] ; then
388\rm $paraminc1
389cat> $paraminc1 <<eod
390logical, save :: first_replay=.true.
391integer, save :: rec_length_replay=0,irec=0
392if (first_replay) then
393eod
394dump_param_open out $varin0 >> $paraminc1
395cat>> $paraminc1 <<eod
396first_replay=.false.
397endif
398irec=irec+1
399write(81,rec=irec) $varin
400eod
401iotd_calls 1     in_${prefix} $var_1D_inout >> $paraminc1
402iotd_calls $klev in_${prefix} $var_2D_inout >> $paraminc1
403fi # nconly = false
404
405if [ "`grep $paraminc1 $paramfile`" = "" ] ; then
406   # Not changing $paraminc1 if it is already included in the file
407   # To allow adding new nc outputs in a routine equiped for replay
408   for var in $var_1D_noarg $var_2D_noarg ; do echo $var=0. >> $paraminc1 ; done
409   include_line "include \"$paraminc1\"" $param $paramfile -after_declarations
410fi
411
412#-----------------------------------------------------------------------------
413# Creating file dump_${param}_nc_${prefix}.h
414#-----------------------------------------------------------------------------
415
416\rm $paraminc2
417iotd_calls 1     "${prefix}" $var_1D >> $paraminc2
418iotd_calls $klev "${prefix}" $var_2D >> $paraminc2
419include_line "include \"$paraminc2\"" $param $paramfile "$where"
420 
421#-----------------------------------------------------------------------------
422# dump_ini_module gere l'ecriture des variables d'interface de l'intialisation
423# du module en mode replay
424#-----------------------------------------------------------------------------
425
426if [ $nconly = false -a $param_ini != None ] ; then
427   varinmod=`grep -i 'intent.in' $inimod.F90 | sed -e 's/\!.*$//' | cut -d: -f3 | sed -e 's/,/ /g'`
428   varinmodv=`echo $varinmod | sed -e 's/ /,/g'`
429   cat > $iniinc <<...eod...............................................
430   open(90,file='$inimod.bin',form='unformatted')
431   write(90) $varinmodv
432   close(90)
433...eod...............................................
434   for var_ in $varinmod ; do echo "print*,'Interface $param_ini $var_',$var_" >> $iniinc ; done
435   include_line "include \"$iniinc\"" $param_ini $inimod.F90  -before_return
436fi # nconly = false
437
438#-----------------------------------------------------------------------------
439# call_ini_replay.F90 gere l'initialisation du module en mode replay
440#-----------------------------------------------------------------------------
441if [ $nconly = false -a $param_ini != None ] ; then
442    cat > call_ini_replay.F90 <<....eod............................................
443    subroutine call_ini_replay
444    use $inimod
445    IMPLICIT NONE
446....eod............................................
447    grep -i intent.in $inimod.F90  |  tr '[A-Z]' '[a-z]' | sed -e 's/,.*intent.i.*)//' >> call_ini_replay.F90
448    cat >> call_ini_replay.F90 <<....eod...........................................
449    open(90,file='$inimod.bin',form='unformatted')
450    read(90) $varinmodv
451    close(90)
452....eod...........................................
453    #get_subroutine_arg $param_ini $inimod.F90 ; exit
454    get_subroutine_arg $param_ini $inimod.F90 | sed -e 's/subroutine/call/' >> call_ini_replay.F90
455    cat >> call_ini_replay.F90 <<....eod...........................................
456    return
457    end
458....eod...........................................
459fi # nconly = false
Note: See TracBrowser for help on using the repository browser.