source: BOL/Replay/replay_equip.sh @ 4659

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

Ajout de ustarhb

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