Script Bash pour automatiser les calculs HPC
Sep 01 2020
Je suis un étudiant en chimie travaillant sur un script bash simple pour automatiser les calculs de théorie fonctionnelle de densité HPC à l'aide de Quantum Espresso (pw.x). Je suis très novice en matière de scripts shell et j'apprécierais quelques critiques / commentaires avant d'essayer de l'implémenter sur le cluster. Le script appelle ingen.py qui est un script Python que j'ai écrit pour générer de nouveaux fichiers d'entrée si certains seuils de paramètres dans le fichier journal ne sont pas atteints.
#!/bin/bash
#SBATCH --job-name=2x2x6_PbCO3 # job name
#SBATCH --output=slurm.out # Output file name
#SBATCH --error=slurm.err # Error file name
#SBATCH --partition=batch # Partition
#SBATCH --qos=medium+ # Queue
#SBATCH --time=24:00:00 # Time limit
#SBATCH --nodes=3 # Number of nodes
#SBATCH --ntasks-per-node=16 # MPI processes per node
errors='MPI_ABORT|error|aborted|SIGTERM|TIME|CANCELLED|SIGCONT|terminated|fork'
job='2x2x6_PbCO3'
max_runs=5
prefix=PbCO3
#-------------------------------------------------------------------------------
Clear ()
{
# Checks for input/log from a completed batch script
if [[ -f "$prefix.in" && -f "$prefix.log" ]]; then
# If both are found a new input file is generated
python ~/path-to-in-gen.py $prefix.log $prefix.in $job override if [ -z "$(ls -A ../logs_and_inputs)" ]; then
index=1
else
indices=()
# Old input/log are tagged and stored
for entry in "../logs_and_inputs"/$prefix.in-*; do indices+=("${entry: -1}")
done
max=${indices[0]} for n in "${indices[@]}" ; do
((n > max)) && max=$n done index=$((max+1))
rm -r *x*x*
mv $prefix.in ../logs_and_inputs/$prefix.in-$index mv $prefix.log ../logs_and_inputs/$prefix.log-$index
mv $prefix.in-new $prefix.in
fi
fi
}
#-------------------------------------------------------------------------------
# Creates a directory for old logs and inputs to be stored with a numerical tag from 1 to k
Sort ()
{
if [ ! -d "../logs_and_inputs" ]; then
mkdir ../logs_and_inputs
iter=1
else
if [ -z "$(ls -A ../logs_and_inputs)" ]; then iter=1 else indices=() for entry in "../logs_and_inputs"/$prefix.in-*; do
indices+=("${entry: -1}") done max=${indices[0]}
for n in "${indices[@]}" ; do ((n > max)) && max=$n
done
iter=$((max+1)) fi fi max_iter=$((iter+max_runs))
}
#-------------------------------------------------------------------------------
Automode ()
{
mpirun ~/path-to-pw.x < $prefix.in > $prefix.log
# Runs pw.x job, checks for completion and errors
if grep -E -q -- $errors "slurm.err"; then exit 1 fi if grep -q "job DONE." "$prefix.log"; then
# Clear wavefunction files and temp directories
rm -r *x*x*
# Generates new input file
python ~/path-to-in-gen.py $prefix.log $prefix.in $job # Tags and stores the previous input and log mv $prefix.in ../logs_and_inputs/$prefix.in-$iter
mv $prefix.log ../logs_and_inputs/$prefix.log-$iter else exit 1 fi # Checks for generation of new input file if test -f "$prefix.in-new"; then
mv $prefix.in-new $prefix.in
else
exit 1
fi
let "iter=iter+1"
}
#-------------------------------------------------------------------------------
Clear
Sort
while ((iter < max_iter)); do
Automode
done
Réponses
4 l0b0 Sep 01 2020 at 10:02
Suggestions spécifiques:
- Les noms de fonction sont par convention
snake_case. - Utilisez More Quotes ™ .
- [[devrait être utilisé à la place[ , car il est plus sûr.
[[ EXPRESSION ]] && [[ EXPRESSION ]]serait plus clair que[[ EXPRESSION && EXPRESSION ]], à mon avis.set -o errexit -o noclobber -o nounset -o pipefailetshopt -s globfailrendrait la gestion des erreurs beaucoup plus stricte.- Ce n'est plus du code trivial, je vous recommande donc de l'implémenter dans un langage non-shell comme Python.
Suggestions d'outils:
- L'exécution
shellcheckrégulière de votre script est un bon moyen de capturer d'éventuels problèmes. Dans ce cas, la seule chose qu'il trouve est pourrm -r *x*x*:SC2035: Utilisez ./ glob ou - glob pour que les noms avec des tirets ne deviennent pas des options.