source: trunk/LMDZ.COMMON/libf/evolution/deftank/lib_launchPEM.sh @ 3939

Last change on this file since 3939 was 3909, checked in by jbclement, 5 months ago

PEM:
Managing automatically the slope variables outputted by XIOS according to 'nslope' to avoid subsequent errors.
JBC

  • Property svn:executable set to *
File size: 18.3 KB
Line 
1#!/bin/bash
2########################################################################
3######## Library of bash functions for the PEM launching script ########
4########################################################################
5
6# To end the launching script
7endlaunch() {
8    # Restore the previous value of LC_NUMERIC
9    LC_NUMERIC=$OLD_LC_NUMERIC
10
11    date
12    echo "Success: the launching script for the PEM simulation completed normally!"
13    exit 0
14}
15
16# To end the launching script with error
17errlaunch() {
18    # Restore the previous value of LC_NUMERIC
19    LC_NUMERIC=$OLD_LC_NUMERIC
20
21    date
22    echo "Error: an issue occured in the launching script for the PEM simulation!"
23    exit 1
24}
25
26# To check what is the job scheduler
27function job_scheduler() {
28    if command -v squeue &> /dev/null; then
29        echo "SLURM is installed on $machine."
30        scheduler="SLURM"
31        name_job="#SBATCH --job-name="
32        kill_job="scancel"
33    elif command -v qstat &> /dev/null; then
34        echo "PBS/TORQUE is installed on $machine."
35        scheduler="PBS"
36        name_job="#PBS -N "
37        kill_job="qdel"
38    else
39        echo "Error: neither SLURM nor TORQUE/PBS is installed on $machine!"
40        echo "You need to adapt the script to your job scheduler or set 'mode' to 0."
41        errlaunch
42    fi
43}
44
45# To get the number of slopes for the simulation
46get_nslope() {
47    ns=1
48    if [ -f "startfi.nc" ]; then
49        ns=$(ncdump -h startfi.nc | sed -n 's/.*nslope = \([0-9]*\) ;.*/\1/p')
50    else
51        for f in run_PCM.def callphys.def; do
52            if [[ -f "$f" ]]; then
53                while IFS= read -r line; do
54                    # Remove leading whitespace
55                    trimmed=$(echo "$line" | sed 's/^[[:space:]]*//')
56                    # Skip lines that are commented out
57                    if [[ "$trimmed" == \#* ]]; then
58                        continue
59                    fi
60                    # Check if line contains 'nslope = N'
61                    if [[ "$trimmed" =~ ^nslope[[:space:]]*=[[:space:]]*([0-9]+) ]]; then
62                        ns="${BASH_REMATCH[1]}"
63                        break
64                    fi
65                done < "$f"
66                [[ -n "$ns" ]] && break
67            fi
68        done
69    fi
70}
71
72# To modify the xml file according nslope
73modify_xml() {
74    tmp="tmp_file_def.xml"
75    in_diurnalave=false
76    in_diurnalave_s=false
77
78    sed -i 's/enabled="\.true\.\">/enabled=".false.">/g' file_def_physics_mars.xml
79
80    while IFS= read -r line; do
81        case "$line" in
82            *'<file id="diurnalave"'*)
83                in_diurnalave=true
84                ;;
85            *'<file id="diurnalave_s"'*)
86                in_diurnalave_s=true
87                ;;
88        esac
89
90        # Handle enabled attribute
91        if [[ $line == *'enabled="'* ]]; then
92            if $in_diurnalave; then
93                if [[ $ns -eq 1 ]]; then
94                    line='              enabled=".true.">'
95                else
96                    line='              enabled=".false.">'
97                fi
98            elif $in_diurnalave_s; then
99                if [[ $ns -eq 1 ]]; then
100                    line='              enabled=".false.">'
101                else
102                    line='              enabled=".true.">'
103                fi
104            fi
105        fi
106
107        # Detect slope variables
108        if $in_diurnalave_s && [[ $line =~ slope([0-9]+) ]]; then
109            slope_id="${BASH_REMATCH[1]}"
110            if (( 10#$slope_id > ns )); then
111                # Ensure the line is commented
112                if [[ $line != "<!--"* ]]; then
113                    line="<!-- $line -->"
114                fi
115            else
116                # Ensure the line is uncommented
117                if [[ $line == "<!--"* ]]; then
118                    line="${line#<!-- }" # remove leading <!--
119                    line="${line% -->}"  # remove trailing -->
120                fi
121            fi
122        fi
123
124        case "$line" in
125            *'</file>'*)
126                in_diurnalave=false
127                in_diurnalave_s=false
128                ;;
129        esac
130
131        echo "$line" >> "$tmp"
132    done < file_def_physics_mars.xml
133
134    mv "$tmp" file_def_physics_mars.xml
135}
136
137# To check if everything necessary for the launching script is ok
138checklaunch() {
139    # Save the current value of LC_NUMERIC and set it to a locale that uses a dot as the decimal separator
140    OLD_LC_NUMERIC=$LC_NUMERIC
141    LC_NUMERIC=en_US.UTF-8
142
143    if [ -v n_mars_years ] && [ ! -z "$n_mars_years" ]; then
144        if [ $(echo "$n_mars_years <= 0." | bc -l) -eq 1 ]; then
145            echo "Error: 'n_mars_years' must be > 0!"
146            errlaunch
147        fi
148    elif [ -v n_earth_years ] && [ ! -z "$n_earth_years" ]; then
149        if [ $(echo "$n_earth_years <= 0." | bc -l) -eq 1 ]; then
150            echo "Error: 'n_earth_years' must be > 0!"
151            errlaunch
152        fi
153    else
154        echo "Error: the number of years to be simulated is not set!"
155        errlaunch
156    fi
157    if [ $nPCM_ini -lt 2 ] || [ -z "$nPCM_ini" ]; then
158        echo "Error: 'nPCM_ini' must be >= 2!"
159        errlaunch
160    fi
161    if [ $nPCM -lt 2 ] || [ -z "$nPCM" ]; then
162        echo "Error: 'nPCM' must be >= 2!"
163        errlaunch
164    fi
165    if [ ! -f "PCMrun.job" ]; then
166        echo "Error: file \"PCMrun.job\" does not exist in $dir!"
167        errlaunch
168    fi
169    if [ ! -f "PEMrun.job" ]; then
170        echo "Error: file \"PEMrun.job\" does not exist in $dir!"
171        errlaunch
172    fi
173    if [ ! -f "run_PCM.def" ]; then
174        echo "Error: file \"run_PCM.def\" does not exist in $dir!"
175        errlaunch
176    fi
177    if [ ! -f "run_PEM.def" ]; then
178        echo "Error: file \"run_PEM.def\" does not exist in $dir!"
179        errlaunch
180    fi
181    if [ ! -f "context_lmdz_physics.xml" ]; then
182        echo "Error: file \"context_lmdz_physics.xml\" does not exist in $dir!"
183        errlaunch
184    fi
185    if [ ! -f "field_def_physics_mars.xml" ]; then
186        echo "Error: file \"field_def_physics_mars.xml\" does not exist in $dir!"
187        errlaunch
188    fi
189    if [ ! -f "file_def_physics_mars.xml" ]; then
190        echo "Error: file \"file_def_physics_mars.xml\" does not exist in $dir!"
191        errlaunch
192    fi
193    if [ ! -f "iodef.xml" ]; then
194        echo "Error: file \"iodef.xml\" does not exist in $dir!"
195        errlaunch
196    fi
197    if [ ! -d "logs" ]; then
198        mkdir logs
199    fi
200    if [ ! -d "starts" ]; then
201        mkdir starts
202    fi
203    if [ ! -d "diags" ]; then
204        mkdir diags
205    fi
206    if [ $mode -ne 0 ]; then
207        job_scheduler
208    fi
209    # Set automatically the XIOS output file for the PEM according to the number of slopes
210    get_nslope
211    modify_xml
212}
213
214# To convert Earth years into Mars years
215convertyears() {
216    myear=686.9725      # Number of Earth days in Martian year
217    eyear=365.256363004 # Number of days in Earth year
218    convert_years=$(echo "$myear/$eyear" | bc -l)
219    convert_years=$(printf "%.4f" $convert_years) # Rounding to the 4th decimal to respect the precision of Martian year
220    if [ -v n_mars_years ]; then
221        n_myear=$n_mars_years
222        echo "Number of years to be simulated: $n_myear Martian years."
223    elif [ -v n_earth_years ]; then
224        n_myear=$(echo "$n_earth_years/$convert_years" | bc -l)
225        echo "Number of years to be simulated: $n_earth_years Earth years = $n_myear Martian years."
226    fi
227}
228
229# To initialize the launching script
230initlaunch() {
231    echo "This is a chained simulation for PEM and PCM runs in $dir on $machine by $user."
232    convertyears
233    i_myear=0.
234    iPEM=1
235    iPCM=1
236    if [ -f "startfi.nc" ]; then
237        cp startfi.nc starts/
238    fi
239    if [ -f "start.nc" ]; then
240        cp start.nc starts/
241    elif [ -f "start1D.txt" ]; then
242        cp start1D.txt starts/
243    fi
244    if [ -f "startpem.nc" ]; then
245        cp startpem.nc starts/
246    fi
247
248    # Create a file to manage years of the chained simulation and store some info from the PEM runs
249    echo $i_myear $n_myear $convert_years $iPCM $iPEM $nPCM $nPCM_ini > info_PEM.txt
250}
251
252# To submit the PCM runs
253# arg1: launching mode
254# arg2: counting method
255# arg3: number of PCM runs to launch
256# arg4: local number of the PCM run from which to start (optional)
257submitPCM() {
258    find . -type f -name "PCMrun*.job" ! -name "PCMrun.job" -delete
259    ii=1
260    if [ ! -z $4 ]; then
261        ii=$4
262    fi
263    if [ $(echo "$i_myear < $n_myear" | bc -l) -eq 1 ]; then
264        echo "Run \"PCM $iPCM\" ($ii/$3)"
265        if [ $1 -eq 0 ]; then # Mode: processing scripts
266            sed -i "s/^k=-\?[0-9]\+$/k=$(echo "$ii - $3 + 2" | bc)/" PCMrun.job
267            ./PCMrun.job
268            if [ $? -ne 0 ]; then
269                errlaunch
270            fi
271        else # Mode: submitting jobs
272            cp PCMrun.job PCMrun${iPCM}.job
273            sed -i -E "/^$name_job/s/(.*[^0-9])([0-9]+)(_[^0-9]*)?$/\1${iPCM}\3/" PCMrun${iPCM}.job
274            sed -i "s/^k=-\?[0-9]\+$/k=$(echo "$ii - $3 + 2" | bc)/" PCMrun${iPCM}.job
275            if [[ "$scheduler" == "SLURM" ]]; then
276                jobID=$(sbatch --parsable PCMrun${iPCM}.job)
277            elif [[ "$scheduler" == "PBS" ]]; then
278                jobID=$(qsub PCMrun${iPCM}.job | cut -d. -f1)
279            fi
280            # Create a file to cancel the dependent jobs of the cycle
281            echo "#!/bin/bash" > kill_launchPEM.sh
282            chmod +x kill_launchPEM.sh
283            echo $kill_job $jobID >> kill_launchPEM.sh
284        fi
285        ((iPCM++))
286        if [ $2 -ne 0 ]; then # Counting: PCM runs taken into account
287            i_myear=$(echo "$i_myear + 1." | bc -l)
288        fi
289        ((ii++))
290    else
291        endlaunch
292    fi
293    for ((i = $ii; i <= $3; i++)); do
294        if [ $(echo "$i_myear < $n_myear" | bc -l) -eq 1 ]; then
295            echo "Run \"PCM $iPCM\" ($i/$3)"
296            if [ $1 -eq 0 ]; then # Mode: processing scripts
297                sed -i "s/^k=-\?[0-9]\+$/k=$(echo "$i - $3 + 2" | bc)/" PCMrun.job
298                ./PCMrun.job
299                if [ $? -ne 0 ]; then
300                    errlaunch
301                fi
302            else # Mode: submitting jobs
303                cp PCMrun.job PCMrun${iPCM}.job
304                sed -i -E "/^$name_job/s/(.*[^0-9])([0-9]+)(_[^0-9]*)?$/\1${iPCM}\3/" PCMrun${iPCM}.job
305                sed -i "s/^k=-\?[0-9]\+$/k=$(echo "$i - $3 + 2" | bc)/" PCMrun${iPCM}.job
306                if [[ "$scheduler" == "SLURM" ]]; then
307                    jobID=$(sbatch --parsable --dependency=afterok:${jobID} PCMrun${iPCM}.job)
308                elif [[ "$scheduler" == "PBS" ]]; then
309                    jobID=$(qsub -W depend=afterok:${jobID} PCMrun${iPCM}.job | cut -d. -f1)
310                fi
311                echo $kill_job $jobID >> kill_launchPEM.sh
312            fi
313            ((iPCM++))
314            if [ $2 -ne 0 ]; then # Counting: PCM runs taken into account
315                i_myear=$(echo "$i_myear + 1." | bc -l)
316            fi
317        else
318            endlaunch
319        fi
320    done
321}
322
323# To submit the PEM run
324# arg1: launching mode
325submitPEM() {
326    if [ $(echo "$i_myear < $n_myear" | bc -l) -eq 1 ]; then
327        echo "Run \"PEM $iPEM\""
328        if [ $1 -eq 0 ]; then # Mode: processing scripts
329            ./PEMrun.job
330            if [ $? -ne 0 ]; then
331                errlaunch
332            fi
333        else # Mode: submitting jobs
334            sed -i -E "/^$name_job/s/(.*[^0-9])([0-9]+)(_[^0-9]*)?$/\1${iPEM}\3/" PEMrun.job
335            if [[ "$scheduler" == "SLURM" ]]; then
336                jobID=$(sbatch --parsable PEMrun.job)
337            elif [[ "$scheduler" == "PBS" ]]; then
338                jobID=$(qsub PEMrun.job | cut -d. -f1)
339            fi
340            # Create a file to cancel the dependent jobs of the cycle
341            echo "#!/bin/bash" > kill_launchPEM.sh
342            chmod +x kill_launchPEM.sh
343            echo $kill_job $jobID >> kill_launchPEM.sh
344        fi
345    else
346        endlaunch
347    fi
348}
349
350# To make one cycle of PCM and PEM runs
351# arg1: launching mode
352# arg2: counting method
353# arg3: number of PCM runs to launch
354# arg4: local number of the PCM run from which to start (optional)
355cyclelaunch() {
356    # PCM runs
357    submitPCM $1 $2 $3 $4
358
359    # PEM run
360    if [ $(echo "$i_myear < $n_myear" | bc -l) -eq 1 ]; then
361        echo "Run \"PEM $iPEM\""
362        if [ $1 -eq 0 ]; then # Mode: processing scripts
363            ./PEMrun.job
364            if [ $? -ne 0 ]; then
365                errlaunch
366            fi
367        else # Mode: submitting jobs
368            sed -i -E "/^$name_job/s/(.*[^0-9])([0-9]+)(_[^0-9]*)?$/\1${iPEM}\3/" PEMrun.job
369            if [[ "$scheduler" == "SLURM" ]]; then
370                jobID=$(sbatch --parsable --dependency=afterok:${jobID} PEMrun.job)
371            elif [[ "$scheduler" == "PBS" ]]; then
372                jobID=$(qsub -W depend=afterok:${jobID} PEMrun.job | cut -d. -f1)
373            fi
374            echo $kill_job $jobID >> kill_launchPEM.sh
375        fi
376    else
377        endlaunch
378    fi
379}
380
381# To clean files after the starting run of the relaunch
382# arg1: file name prefix to clean
383# arg2: file name extension to clean
384# arg3: file number from which to clean
385cleanfiles() {
386    prefix=$1
387    extension=$2
388    if [ -z "$extension" ]; then
389        for file in ${prefix}*; do
390            num=${file#$prefix}
391            if [[ $num =~ ^[0-9]+$ ]] && [ $num -gt $3 ]; then
392                rm $file
393            fi
394        done
395    else
396        for file in ${prefix}*${extension}; do
397            num=${file#$prefix}
398            num=${num%$extension}
399            if [[ $num =~ ^[0-9]+$ ]] && [ $num -gt $3 ]; then
400                rm $file
401            fi
402        done
403    fi
404}
405
406# To relaunch from PCM run
407# arg1: launching mode
408# arg2: counting method
409relaunchPCM() {
410    iPCM=$(($irelaunch + 1))
411    cleanfiles diags/diagfi .nc $irelaunch
412    cleanfiles diags/diagsoil .nc $irelaunch
413    cleanfiles diags/data2reshape .nc $irelaunch
414    cleanfiles logs/runPCM .log $irelaunch
415    cleanfiles starts/restart1D .txt $irelaunch
416    cleanfiles starts/restart .nc $irelaunch
417    cleanfiles starts/restartfi .nc $irelaunch
418    cp starts/restartfi${irelaunch}.nc startfi.nc
419    if [ -f "starts/restart${irelaunch}.nc" ]; then
420        cp starts/restart${irelaunch}.nc start.nc
421    elif [ -f "starts/restart1D${irelaunch}.txt" ]; then
422        cp starts/restart1D${irelaunch}.txt start1D.txt
423    fi
424    if [ $irelaunch -le $nPCM_ini ]; then
425        # PCM relaunch during the initialization cycle
426        iPEM=1
427        if [ $2 -ne 0 ]; then # Counting: PCM runs taken into account
428            i_myear=$irelaunch
429        else # Counting: only PEM runs count
430            i_myear=0
431        fi
432        sed -i "1s/.*/$i_myear $n_myear $convert_years $iPCM $iPEM $nPCM $nPCM_ini/" info_PEM.txt
433        cleanfiles diags/diagpem .nc $(($iPEM - 1))
434        cleanfiles diags/diagsoilpem .nc $(($iPEM - 1))
435        cleanfiles logs/runPEM .log $(($iPEM - 1))
436        cleanfiles starts/restart1D_postPEM .txt $(($iPEM - 1))
437        cleanfiles starts/restart_postPEM .nc $(($iPEM - 1))
438        cleanfiles starts/restartfi_postPEM .nc $(($iPEM - 1))
439        cleanfiles starts/restartpem .nc $(($iPEM - 1))
440        rm -f startpem.nc
441        if [ -f "starts/startpem.nc" ]; then
442            cp starts/startpem.nc .
443        fi
444        if [ $irelaunch -eq $(($nPCM_ini - 1)) ]; then
445            cp diags/data2reshape${irelaunch}.nc data2reshape_Y1.nc
446            cyclelaunch $1 $2 $nPCM_ini $iPCM
447        elif [ $irelaunch -eq $nPCM_ini ]; then
448            cp diags/data2reshape$(($irelaunch - 1)).nc data2reshape_Y1.nc
449            cp diags/data2reshape${irelaunch}.nc data2reshape_Y2.nc
450            submitPEM $1 # The next job is a PEM run
451        else
452            cyclelaunch $1 $2 $nPCM_ini $iPCM
453        fi
454    else
455        # PCM relaunch during a cycle
456        iPEM=$(echo "($iPCM - $nPCM_ini)/$nPCM + 1" | bc)
457        il=$(echo "($irelaunch - $nPCM_ini + 1)%$nPCM + 1" | bc)
458        if [ $2 -ne 0 ]; then # Counting: PCM runs taken into account
459            i_myear=$(echo "$(awk "NR==$iPEM {printf \"%s\n\", \$3}" "info_PEM.txt") + $il" | bc -l)
460        else # Counting: only PEM runs count
461            i_myear=$(awk "NR==$iPEM {printf \"%s\n\", \$3}" "info_PEM.txt")
462        fi
463        sed -i "1s/.*/$i_myear $n_myear $convert_years $iPCM $iPEM $nPCM $nPCM_ini/" info_PEM.txt
464        cleanfiles diags/diagpem .nc $(($iPEM - 1))
465        cleanfiles diags/diagsoilpem .nc $(($iPEM - 1))
466        cleanfiles logs/runPEM .log $(($iPEM - 1))
467        cleanfiles starts/restart1D_postPEM .txt $(($iPEM - 1))
468        cleanfiles starts/restart_postPEM .nc $(($iPEM - 1))
469        cleanfiles starts/restartfi_postPEM .nc $(($iPEM - 1))
470        cleanfiles starts/restartpem .nc $(($iPEM - 1))
471        cp starts/restartpem$(($iPEM - 1)).nc startpem.nc
472        if [ $il -eq $(($nPCM - 1)) ]; then # Second to last PCM run
473            cp diags/data2reshape${irelaunch}.nc data2reshape_Y1.nc
474            cyclelaunch $1 $2 $nPCM $(($il + 1))
475        elif [ $il -eq $nPCM ]; then # Last PCM run so the next job is a PEM run
476            cp diags/data2reshape$(($irelaunch - 1)).nc data2reshape_Y1.nc
477            cp diags/data2reshape${irelaunch}.nc data2reshape_Y2.nc
478            submitPEM $1
479        else
480            cyclelaunch $1 $2 $nPCM $(($il + 1))
481        fi
482    fi
483}
484
485# To relaunch from PEM run
486# arg1: launching mode
487# arg2: counting method
488relaunchPEM() {
489    iPEM=$(echo "$irelaunch + 1" | bc)
490    iPCM=$(echo "$nPCM_ini + $nPCM*($irelaunch - 1) + 1" | bc)
491    i_myear=$(awk "NR==$iPEM {printf \"%s\n\", \$3}" "info_PEM.txt")
492    sed -i "1s/.*/$i_myear $n_myear $convert_years $iPCM $iPEM $nPCM $nPCM_ini/" info_PEM.txt
493    cleanfiles diags/diagfi .nc $(($iPCM - 1))
494    cleanfiles diags/diagsoil .nc $(($iPCM - 1))
495    cleanfiles logs/runPCM .log $(($iPCM - 1))
496    cleanfiles starts/restart1D .txt $(($iPCM - 1))
497    cleanfiles starts/restart .nc $(($iPCM - 1))
498    cleanfiles starts/restartfi .nc $(($iPCM - 1))
499    cleanfiles diags/data2reshape .nc $(($iPCM - 1))
500    cleanfiles diags/diagpem .nc $irelaunch
501    cleanfiles diags/diagsoilpem .nc $irelaunch
502    cleanfiles logs/runPEM .log $irelaunch
503    cleanfiles starts/restart1D_postPEM .txt $irelaunch
504    cleanfiles starts/restart_postPEM .nc $irelaunch
505    cleanfiles starts/restartfi_postPEM .nc $irelaunch
506    cleanfiles starts/restartpem .nc $irelaunch
507    cp starts/restartpem${irelaunch}.nc startpem.nc
508    cp starts/restartfi_postPEM${irelaunch}.nc startfi.nc
509    if [ -f "starts/restart_postPEM${irelaunch}.nc" ]; then
510        cp starts/restart_postPEM${irelaunch}.nc start.nc
511    elif [ -f "starts/restart1D_postPEM${irelaunch}.txt" ]; then
512        cp starts/restart1D_postPEM${irelaunch}.txt start1D.txt
513    fi
514    cyclelaunch $1 $2 $nPCM
515}
Note: See TracBrowser for help on using the repository browser.